samskalicky commented on a change in pull request #15921: [WIP] dynamic custom
operator support
URL: https://github.com/apache/incubator-mxnet/pull/15921#discussion_r321954930
##########
File path: include/mxnet/lib_api.h
##########
@@ -18,33 +18,627 @@
*/
/*!
- * Copyright (c) 2015 by Contributors
+ * Copyright (c) 2019 by Contributors
* \file lib_api.h
* \brief APIs to interact with libraries
+ * This API specifies function prototypes to
+ * register custom ops for library authors
*/
+
#ifndef MXNET_LIB_API_H_
#define MXNET_LIB_API_H_
+#include <stdint.h>
+#include <vector>
+#include <map>
+#include <string>
+
+#define MX_LIBRARY_VERSION 1
+
/*!
- * \brief Following are the APIs implemented in the external library
+ * \brief External Tensor data types
+ */
+enum MXDType {
+ kFloat32 = 0,
+ kFloat64 = 1,
+ kFloat16 = 2,
+ kUint8 = 3,
+ kInt32 = 4,
+ kInt8 = 5,
+ kInt64 = 6,
+};
+
+enum MXReturnValue {
+ MX_FAIL = 0,
+ MX_SUCCESS = 1,
+};
+
+/*!
+ * \brief External Tensor data structure
+ */
+struct MXTensor {
+ MXTensor() : data(nullptr) {}
+
+ MXTensor(void *data, const std::vector<int64_t> &shape, MXDType dtype)
+ : data{data}, shape{shape}, dtype{dtype} {}
+
+ /*!
+ * \brief helper function to cast data pointer
+ */
+ template<typename data_type>
+ data_type* getData() {
+ return reinterpret_cast<data_type*>(data);
+ }
+
+ void *data; // not owned
+ std::vector<int64_t> shape;
+ MXDType dtype;
+};
+
+/*!
+ * \brief resource malloc function to allocate memory inside fcompute function
+ */
+typedef void* (*xpu_malloc_t)(void*, int);
+
+/*!
+ * \brief Class to provide resource APIs to FCompute
+ */
+class OpResource {
+ public:
+ OpResource(xpu_malloc_t xm, void* _xm) : xpu_malloc(xm), _xpu_malloc(_xm) {}
+
+ /*!
+ * \brief allocate memory controlled by MXNet
+ */
+ void* alloc(int size) {
+ return xpu_malloc(_xpu_malloc, size);
+ }
+ private:
+ xpu_malloc_t xpu_malloc;
+ void* _xpu_malloc;
+};
+
+/*!
+ * \brief StatefulOp wrapper class to pass to backend OpState
+ */
+class CustomStatefulOpWrapper {
+ public:
+ CustomStatefulOpWrapper(void* inst) : instance(inst) {}
+ void* get_instance() { return instance; }
+ private:
+ void* instance;
+};
+
+/*!
+ * \brief An prototype interface class for library author creating stateful op
+ */
+class CustomStatefulOp {
+ public:
+ virtual void Forward() = 0;
+ virtual ~CustomStatefulOp() = 0;
+};
+
+/*!
+ * Custom Operator function templates
+ */
+typedef MXReturnValue (*fcomp_t)(std::map<std::string, std::string>,
+ std::vector<MXTensor>, std::vector<MXTensor>,
+ OpResource res);
+typedef MXReturnValue (*parseAttrs_t)(std::map<std::string, std::string>,
+ int*, int*);
+typedef MXReturnValue (*inferType_t)(std::map<std::string, std::string>,
+ std::vector<int>&, std::vector<int>&);
+typedef MXReturnValue (*inferShape_t)(std::map<std::string, std::string>,
+ std::vector<std::vector<unsigned int>>&,
+ std::vector<std::vector<unsigned int>>&);
+typedef MXReturnValue (*mutateInputs_t)(std::map<std::string, std::string>,
+ std::vector<int>&);
+typedef MXReturnValue (*createOpState_t)(std::map<std::string, std::string>,
+ CustomStatefulOp**);
+typedef MXReturnValue (*fstateful_t)(CustomStatefulOp*, std::vector<MXTensor>,
+ std::vector<MXTensor>);
+
+/*!
+ * \brief Class to hold custom operator registration
+ */
+class CustomOp {
+ public:
+ explicit CustomOp(const char* op_name) : name(op_name), fcompute(nullptr),
+ fgradient(nullptr), parse_attrs(nullptr), infer_type(nullptr),
infer_shape(nullptr),
+ mutate_inputs(nullptr), create_op_state(nullptr), fstateful(nullptr) {}
+ ~CustomOp() {}
+ CustomOp& setForward(fcomp_t fcomp) {
+ fcompute = fcomp;
+ return *this;
+ }
+ CustomOp& setGradient(fcomp_t fcomp) {
+ fgradient = fcomp;
+ return *this;
+ }
+ CustomOp& setParseAttrs(parseAttrs_t func) {
+ parse_attrs = func;
+ return *this;
+ }
+ CustomOp& setInferType(inferType_t func) {
+ infer_type = func;
+ return *this;
+ }
+ CustomOp& setInferShape(inferShape_t func) {
+ infer_shape = func;
+ return *this;
+ }
+ CustomOp& setMutateInputs(mutateInputs_t func) {
+ mutate_inputs = func;
+ return *this;
+ }
+ CustomOp& setCreateOpState(createOpState_t func) {
+ create_op_state = func;
+ return *this;
+ }
+ CustomOp& setForwardStateful(fstateful_t func) {
+ fstateful = func;
+ return *this;
+ }
+ /*! \brief operator name */
+ const char* name;
+ /*! \brief operator functions */
+ fcomp_t fcompute;
+ fcomp_t fgradient;
+ parseAttrs_t parse_attrs;
+ inferType_t infer_type;
+ inferShape_t infer_shape;
+ mutateInputs_t mutate_inputs;
+ createOpState_t create_op_state;
+ fstateful_t fstateful;
+};
+
+/*!
+ * \brief Registry class to registers things (ops, properties)
+ * Singleton class
+ */
+template <class T>
+class Registry {
+ public:
+ /*!
+ * \brief get singleton pointer to class
+ * \returns pointer to class
+ */
+ static Registry* get() {
+ static Registry inst;
+ return &inst;
+ }
+ /*!
+ * \brief add a new entry
+ * \returns new object associated with registered name
+ */
+ T& add(const char* name) {
+ T *entry = new T(name);
+ entries.push_back(entry);
+ return *entry;
+ }
+ int size() {
+ return entries.size();
+ }
+ T& get(int idx) {
+ return *(entries[idx]);
+ }
+
+ private:
+ /*! \brief constructor */
+ Registry() {}
+ /*! \brief destructor */
+ ~Registry() {}
+ /*! \brief map of entries in registry */
+ std::vector<T*> entries;
+};
+
+/*
+ * Macros to help with string concat
+ * Annoyingly, the concat_ and concat macros are necessary to
+ * be able to use __COUNTER__ in an identifier name
+ */
+#define _STR_CONCAT_(__a, __b) __a ## __b
+#define _STR_CONCAT(__a, __b) _STR_CONCAT_(__a, __b)
+
+/*!
+ * \brief convert a token to a string
+ */
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+/*!
+ * \brief declare a variable with custom name
+ */
+#define _REGISTER_NAME_(Name) MXNet ## _CustomOp ## _
+#define _REGISTER_DEF_(Name) CustomOp _REGISTER_NAME_(Name)
+
+/*!
+ * \brief assign a var to a value
+ */
+#define REGISTER_OP(Name) _STR_CONCAT(_REGISTER_DEF_(Name), __COUNTER__) = \
+ Registry<CustomOp>::get()->add(TOSTRING(Name))
+
+/*
+ * -------------- BELOW FUNCTIONS ARE USED IN MXNET BACKEND ---------------
+ */
+
+/*!
+ * \brief Following are the C type APIs implemented in the external library
* Each API has a #define string that is used to lookup the function in the
library
* Followed by the function declaration
*/
+
+#define MXLIB_OPREGSIZE_STR "_opRegSize"
+typedef int (*opRegSize_t)(void);
+
+#define MXLIB_OPREGGET_STR "_opRegGet"
+typedef int (*opRegGet_t)(int, const char**, fcomp_t*, fcomp_t*,
+ parseAttrs_t*, inferType_t*,
+ inferShape_t*, mutateInputs_t*,
+ createOpState_t*, fstateful_t*);
+
+#define MXLIB_OPCALLFREE_STR "_opCallFree"
+typedef int (*opCallFree_t)(void*);
+
+#define MXLIB_OPCALLPARSEATTRS_STR "_opCallParseAttrs"
+typedef int (*opCallParseAttrs_t)(parseAttrs_t, const char* const*, const
char* const*, int,
+ int*, int*);
+
+#define MXLIB_OPCALLINFERSHAPE_STR "_opCallInferShape"
+typedef int (*opCallInferShape_t)(inferShape_t, const char* const*, const
char* const*, int,
+ unsigned int**, int*, int,
+ unsigned int***, int**, int);
+
+#define MXLIB_OPCALLINFERTYPE_STR "_opCallInferType"
+typedef int (*opCallInferType_t)(inferType_t, const char* const*, const char*
const*, int,
+ int*, int, int*, int);
+
+#define MXLIB_OPCALLFCOMP_STR "_opCallFCompute"
+typedef int (*opCallFComp_t)(fcomp_t, const char* const*, const char* const*,
int,
+ const int64_t**, int*, void**, int*, int,
+ const int64_t**, int*, void**, int*, int,
+ xpu_malloc_t, void*);
+
+#define MXLIB_OPCALLMUTATEINPUTS_STR "_opCallMutateInputs"
+typedef int (*opCallMutateInputs_t)(mutateInputs_t, const char* const*, const
char* const*, int,
+ int**, int*);
+
+#define MXLIB_OPCALLCREATEOPSTATE_STR "_opCallCreateOpState"
+typedef int (*opCallCreateOpState_t)(createOpState_t, const char* const*,
const char* const*, int,
+ void**);
+
+#define MXLIB_OPCALLFSTATEFUL_STR "_opCallFStateful"
+typedef int (*opCallFStateful_t)(fstateful_t, void*,
+ const int64_t**, int*, void**, int*, int,
+ const int64_t**, int*, void**, int*, int);
Review comment:
We need to enable OpResource for Stateful ops too like we do with FCompute
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services