|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /**
- * \file python_module/src/cpp/bfloat16.cpp
- *
- * This file is part of MegBrain, a deep learning framework developed by Megvii.
- *
- * \brief numpy dtypes for bfloat16
- *
- * \copyright Copyright (c) 2014-2020 Megvii Inc. All rights reserved.
- *
- */
-
- #include "megbrain/common.h"
- #include "megbrain/dtype.h"
-
- #include <Python.h>
- #include <structmember.h>
-
- #define NO_IMPORT_ARRAY 1
- #include "./numpy_incl.h"
-
- #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-
- namespace {
-
- struct BFloat16Type {
- static int npy_typenum;
- mgb::dt_bfloat16 value;
-
- struct PyObj;
- struct NpyType;
-
- template <typename S, typename T>
- struct NpyCast;
- };
-
- int BFloat16Type::npy_typenum;
-
- /* ==================== BFloat16Type::NpyCast ==================== */
-
- template <typename S>
- struct BFloat16Type::NpyCast<S, BFloat16Type> {
- static void apply(void* from_, void* to_, npy_intp n, void* /*fromarr*/,
- void* /*toarr*/) {
- auto from = static_cast<S*>(from_);
- auto to = static_cast<BFloat16Type*>(to_);
- for (npy_intp i = 0; i < n; ++i) {
- float cur = static_cast<float>(from[i]);
- to[i].value = cur;
- }
- }
- };
-
- template <typename T>
- struct BFloat16Type::NpyCast<BFloat16Type, T> {
- static void apply(void* from_, void* to_, npy_intp n, void* /*fromarr*/,
- void* /*toarr*/) {
- auto from = static_cast<BFloat16Type*>(from_);
- auto to = static_cast<T*>(to_);
- for (npy_intp i = 0; i < n; ++i) {
- to[i] = from[i].value;
- }
- }
- };
-
- /* ==================== BFloat16Type::PyObj ==================== */
- struct BFloat16Type::PyObj {
- PyObject_HEAD BFloat16Type obj;
-
- static PyTypeObject py_type;
-
- static PyObject* from_bfloat16(BFloat16Type val) {
- auto p = reinterpret_cast<PyObj*>(py_type.tp_alloc(&py_type, 0));
- p->obj.value = val.value;
- return reinterpret_cast<PyObject*>(p);
- }
-
- static PyObject* py_new(PyTypeObject* type, PyObject* args, PyObject* kwds);
- static PyObject* py_repr(PyObject* obj);
- static PyObject* py_richcompare(PyObject* a, PyObject* b, int op);
- };
- PyTypeObject BFloat16Type::PyObj::py_type;
-
- PyObject* BFloat16Type::PyObj::py_new(PyTypeObject* type, PyObject* args,
- PyObject* kwds) {
- PyObj* self;
- Py_ssize_t size;
-
- self = (PyObj*)type->tp_alloc(type, 0);
-
- size = PyTuple_GET_SIZE(args);
- if (size > 1) {
- PyErr_SetString(PyExc_TypeError, "BFloat16Type Only has 1 parameter");
- return NULL;
- }
- PyObject* x = PyTuple_GET_ITEM(args, 0);
- if (PyObject_IsInstance(x, (PyObject*)&py_type)) {
- Py_INCREF(x);
- return x;
- }
-
- if (!PyFloat_Check(x)) {
- PyErr_SetString(PyExc_TypeError,
- "BFloat16Type must be initialized wit float");
- return NULL;
- }
-
- const float s = PyFloat_AsDouble(x);
-
- self->obj.value = s;
-
- return (PyObject*)self;
- }
-
- PyObject* BFloat16Type::PyObj::py_repr(PyObject* obj) {
- float fval = static_cast<float>(((PyObj*)obj)->obj.value);
- return PyUnicode_FromString(mgb::ssprintf("%f", fval).c_str());
- }
-
- PyObject* BFloat16Type::PyObj::py_richcompare(PyObject* a, PyObject* b,
- int op) {
- mgb_assert(PyObject_IsInstance(a, (PyObject*)&py_type));
- auto bval = PyFloat_AsDouble(b);
- if (bval == -1 && PyErr_Occurred()) {
- return NULL;
- }
- double aval = ((PyObj*)a)->obj.value;
- #define OP(py, op) \
- case py: { \
- if (aval op bval) { \
- Py_RETURN_TRUE; \
- } else { \
- Py_RETURN_FALSE; \
- } \
- }
- switch (op) {
- OP(Py_LT, <)
- OP(Py_LE, <=)
- OP(Py_EQ, ==)
- OP(Py_NE, !=)
- OP(Py_GT, >)
- OP(Py_GE, >=)
- };
- #undef OP
- return Py_NotImplemented;
- }
-
- /* ==================== BFloat16Type<N>::NpyType ==================== */
- struct BFloat16Type::NpyType {
- static PyArray_ArrFuncs funcs;
- static PyArray_Descr descr;
-
- static bool init();
-
- static void copyswap(void* dst, void* src, int swap, void* /*arr*/) {
- if (src) {
- mgb_assert(!swap);
- memcpy(dst, src, sizeof(BFloat16Type));
- }
- }
- static PyObject* getitem(void* data, void* ap) {
- return BFloat16Type::PyObj::from_bfloat16(
- *static_cast<BFloat16Type*>(data));
- }
- static int setitem(PyObject* op, void* ov, void* ap);
- };
-
- PyArray_ArrFuncs BFloat16Type::NpyType::funcs;
- PyArray_Descr BFloat16Type::NpyType::descr;
-
- int BFloat16Type::NpyType::setitem(PyObject* op, void* ov, void* ap) {
- if (PyLong_Check(op)) {
- int a = PyLong_AsLong(op);
- static_cast<BFloat16Type*>(ov)->value = a;
- } else if (PyFloat_Check(op)) {
- float a = PyFloat_AsDouble(op);
- static_cast<BFloat16Type*>(ov)->value = a;
- } else if (PyObject_IsInstance(
- op, (PyObject*)(&(BFloat16Type::PyObj::py_type)))) {
- static_cast<BFloat16Type*>(ov)->value = ((PyObj*)op)->obj.value;
- } else {
- PyErr_SetString(PyExc_ValueError,
- "input type must be int/float/bfloat16");
- return -1;
- }
- return 0;
- }
-
- bool BFloat16Type::NpyType::init() {
- descr = {PyObject_HEAD_INIT(0) & BFloat16Type::PyObj::py_type,
- 'V', // kind
- 'f', // type
- '=', // byteorder
- NPY_NEEDS_PYAPI | NPY_USE_GETITEM | NPY_USE_SETITEM,
- 1, // type num
- sizeof(BFloat16Type),
- alignof(BFloat16Type),
- NULL,
- NULL,
- NULL,
- &funcs};
- Py_TYPE(&descr) = &PyArrayDescr_Type;
- PyArray_InitArrFuncs(&funcs);
- funcs.copyswap = copyswap;
- funcs.getitem = getitem;
- funcs.setitem = setitem;
- npy_typenum = PyArray_RegisterDataType(&descr);
-
- #define REGISTER_CAST(From, To, From_descr, To_typenum, safe) \
- { \
- PyArray_Descr* from_descr = (From_descr); \
- if (PyArray_RegisterCastFunc(from_descr, (To_typenum), \
- NpyCast<From, To>::apply) < 0) { \
- return false; \
- } \
- if (safe && PyArray_RegisterCanCast(from_descr, (To_typenum), \
- NPY_NOSCALAR) < 0) { \
- return false; \
- } \
- }
- #define REGISTER_INT_CASTS(bits) \
- REGISTER_CAST(npy_int##bits, BFloat16Type, \
- PyArray_DescrFromType(NPY_INT##bits), \
- BFloat16Type::npy_typenum, 1) \
- REGISTER_CAST(BFloat16Type, npy_int##bits, &descr, NPY_INT##bits, 0) \
- REGISTER_CAST(npy_uint##bits, BFloat16Type, \
- PyArray_DescrFromType(NPY_UINT##bits), \
- BFloat16Type::npy_typenum, 1) \
- REGISTER_CAST(BFloat16Type, npy_uint##bits, &descr, NPY_UINT##bits, 0)
-
- REGISTER_INT_CASTS(8)
- REGISTER_INT_CASTS(16)
- REGISTER_INT_CASTS(32)
- REGISTER_INT_CASTS(64)
- REGISTER_CAST(BFloat16Type, float, &descr, NPY_FLOAT, 0)
- REGISTER_CAST(float, BFloat16Type, PyArray_DescrFromType(NPY_FLOAT),
- BFloat16Type::npy_typenum, 0)
- REGISTER_CAST(BFloat16Type, double, &descr, NPY_DOUBLE, 1)
- REGISTER_CAST(double, BFloat16Type, PyArray_DescrFromType(NPY_DOUBLE),
- BFloat16Type::npy_typenum, 0)
- return true;
- }
-
- } // anonymous namespace
-
- bool init_pytype_bfloat16() {
- auto& py_type = BFloat16Type::PyObj::py_type;
- py_type = {PyVarObject_HEAD_INIT(NULL, 0)};
- py_type.tp_name = "megbrain._mgb.pybfloat16";
- py_type.tp_basicsize = sizeof(BFloat16Type::PyObj);
- py_type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
- py_type.tp_doc = "bfloat16 type";
- py_type.tp_new = BFloat16Type::PyObj::py_new;
- py_type.tp_str = BFloat16Type::PyObj::py_repr;
- py_type.tp_repr = BFloat16Type::PyObj::py_repr;
- py_type.tp_richcompare = BFloat16Type::PyObj::py_richcompare;
- py_type.tp_base = &PyGenericArrType_Type;
- return PyType_Ready(&py_type) >= 0;
- }
-
- void register_pytype_bfloat16(PyObject* d, PyObject* m) {
- Py_INCREF(&BFloat16Type::PyObj::py_type);
- PyDict_SetItemString(d, "bfloat16_pytype",
- (PyObject*)&BFloat16Type::PyObj::py_type);
- PyModule_AddObject(m, "bfloat16_pytype",
- (PyObject*)&BFloat16Type::PyObj::py_type);
- }
-
- //! called from swig init
- void _init_bfloat16_types(PyObject* m) {
- if (m == NULL)
- return;
- PyObject* d = PyModule_GetDict(m);
- PyArray_Descr* dtype;
- if (!init_pytype_bfloat16())
- return;
- if (!BFloat16Type::NpyType::init())
- return;
- dtype = PyArray_DescrFromType(BFloat16Type::npy_typenum);
- if (!dtype)
- return;
- {
- PyObject* pytype = (PyObject*)(&BFloat16Type::PyObj::py_type);
- Py_INCREF(pytype);
- PyDict_SetItemString(d, "pybfloat16", pytype);
- }
- Py_INCREF(dtype);
- PyDict_SetItemString(d, "bfloat16", (PyObject*)dtype);
- register_pytype_bfloat16(d, m);
- return;
- }
-
- int mgb::npy_num_bfloat16() {
- return BFloat16Type::npy_typenum;
- }
-
- // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}
|