Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Dynamic subgraph property #17034

Merged
merged 71 commits into from
Jan 9, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
cf30d30
initial commit
Dec 10, 2019
58a41ff
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Dec 10, 2019
702cf50
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Dec 11, 2019
d17a118
added subgraphCreate API function to partition the model/graph
Dec 11, 2019
e05d4e1
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Dec 12, 2019
d0f2fb3
cleaned up API, added API to specify subgraphOp
Dec 12, 2019
55e8861
fixed whitespace
samskalicky Dec 12, 2019
8c97c45
added custom subgraph property
samskalicky Dec 12, 2019
0ebf5b6
fixed whitespace
samskalicky Dec 12, 2019
84f8426
fixed subgraph property
samskalicky Dec 12, 2019
2a1c6fe
fixed whitespace
samskalicky Dec 12, 2019
d3c277d
added registration of custom subgraph property in c_api
samskalicky Dec 12, 2019
55e0974
added support for calling supportOps from customSubgraphProperty
samskalicky Dec 13, 2019
060c8b6
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 13, 2019
6a7e3f7
sending symbol json to supportedOps API
samskalicky Dec 13, 2019
0488879
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 14, 2019
fa206e4
working partitioning example
samskalicky Dec 14, 2019
79d08ea
fixed whitespace
samskalicky Dec 14, 2019
bbe4062
fixed whitespace
samskalicky Dec 14, 2019
a418301
fixed style
samskalicky Dec 14, 2019
420e77a
fixed style
samskalicky Dec 14, 2019
2f354a4
Annotate the symbol json string with shape/type info from the graph o…
samskalicky Dec 15, 2019
92e6f00
Support multiple supportOps functions grouped together. Similar to ho…
samskalicky Dec 15, 2019
901d308
fixed whitespace
samskalicky Dec 15, 2019
053f14e
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 16, 2019
9b160d6
changed vector to unordered_set for performance
samskalicky Dec 16, 2019
ea29e4b
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 17, 2019
bd79319
fixed clearing supportedNodes set after multiple calls
samskalicky Dec 17, 2019
1e41f8e
changed types to int64_t for tensor sizes, fixed indent
samskalicky Dec 17, 2019
e41c50d
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 18, 2019
dd2de0a
added support for passing options to supportedOps
samskalicky Dec 18, 2019
7ea4330
new API to to review subgraphs after partitioning
samskalicky Dec 19, 2019
022b709
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 19, 2019
2f54b12
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 22, 2019
65b30e8
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 27, 2019
b4b4862
added function to revert subgraphing if rejected by subgraph prop
samskalicky Dec 27, 2019
1b3506a
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 28, 2019
cb199cc
added infrastructure to test subgraph libs in the CI
samskalicky Dec 28, 2019
241b591
fixed whitespace
samskalicky Dec 28, 2019
25b71fb
changed default context to CPU since GPU is not supported yet
samskalicky Dec 28, 2019
a53277d
fixed
samskalicky Dec 29, 2019
2fd7423
added include
samskalicky Dec 29, 2019
8434bd8
fixed return types
samskalicky Dec 29, 2019
3ca5882
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 30, 2019
65012cd
added memory free in error condition
samskalicky Dec 30, 2019
d8cbfeb
added clearer function comment
samskalicky Dec 30, 2019
9ddf449
added file comment
samskalicky Dec 30, 2019
17b7631
added more prints in example test for clarity
samskalicky Dec 30, 2019
d0f2efb
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Dec 31, 2019
fc70db3
enhancements from review
samskalicky Dec 31, 2019
fcf483c
retrigger CI
samskalicky Dec 31, 2019
d915dc6
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 2, 2020
71109ce
stopped passing bool types across ABI boundary (changed to int)
samskalicky Jan 2, 2020
5810a16
removed subgraph op from custom_op example
samskalicky Jan 3, 2020
27d0b20
changed subgraph example to use isSubgraphOp
samskalicky Jan 3, 2020
4278d22
added functionality to set "isArg" attribute for subgraph inputs
samskalicky Jan 3, 2020
4e5d849
added comment
samskalicky Jan 3, 2020
034cb89
added functionality to set aux attribute for inputs to subgraph
samskalicky Jan 3, 2020
1ffabfb
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 3, 2020
584c0f6
fixed whitespace and cmakelists
samskalicky Jan 3, 2020
e09750a
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 4, 2020
d7e5dbb
changed acceptSubgraph API to let library set attributes on subgraph …
samskalicky Jan 4, 2020
add02d1
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 4, 2020
34ff989
fixed whitespace
samskalicky Jan 4, 2020
dda4c86
fixed seconds
samskalicky Jan 5, 2020
1931599
retrigger ci
samskalicky Jan 5, 2020
31473ba
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 7, 2020
39ed299
removed unused code
samskalicky Jan 7, 2020
13cfc1c
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 7, 2020
967787e
fixed variable naming
samskalicky Jan 7, 2020
f90df49
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
samskalicky Jan 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 12 additions & 24 deletions example/extensions/lib_subgraph/subgraph_lib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,6 @@
#include <algorithm>
#include "lib_api.h"

MXReturnValue parseAttrs(std::map<std::string, std::string> attrs,
int* num_in, int* num_out) {
*num_in = 1;
*num_out = 1;
if (attrs.count(SUBGRAPH_SYM_JSON)) {
// example of subgraph json parsing
JsonParser jp;
JsonVal val = jp.parse_to_json(attrs[SUBGRAPH_SYM_JSON]);
int input = 0;
for (auto &item : val.map[JsonVal("nodes")].list) {
if (item.map[JsonVal("op")].str == "null")
input++;
}
int output = val.map[JsonVal("heads")].list.size();
*num_in = input;
*num_out = output;
}
return MX_SUCCESS;
}

/* function to execute log operator on floats */
void myLog(MXTensor &in, MXTensor &out) {
samskalicky marked this conversation as resolved.
Show resolved Hide resolved
float* inp = in.data<float>();
Expand Down Expand Up @@ -157,7 +137,12 @@ MXReturnValue myExecutor(std::vector<MXTensor> inputs,

class MyStatefulOp : public CustomStatefulOp {
public:
explicit MyStatefulOp(std::string sym) : subgraph_sym(sym) {}
explicit MyStatefulOp(std::string sym, std::map<std::string, std::string> attrs)
: subgraph_sym(sym), attrs_(attrs) {
for (auto kv : attrs) {
std::cout << "subgraphOp attributes: " << kv.first << " ==> " << kv.second << std::endl;
}
}

MXReturnValue Forward(std::vector<MXTensor> inputs,
std::vector<MXTensor> outputs,
samskalicky marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -167,6 +152,7 @@ class MyStatefulOp : public CustomStatefulOp {

private:
std::string subgraph_sym;
std::map<std::string, std::string> attrs_;
};

MXReturnValue createOpState(std::map<std::string, std::string> attrs,
samskalicky marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -178,13 +164,13 @@ MXReturnValue createOpState(std::map<std::string, std::string> attrs,
// user can now parse json and run other custom ops inside subgraph
serialized_subgraph = attrs[SUBGRAPH_SYM_JSON];
}
*op_inst = new MyStatefulOp(serialized_subgraph);
attrs.erase(SUBGRAPH_SYM_JSON);
*op_inst = new MyStatefulOp(serialized_subgraph, attrs);
std::cout << "Info: stateful operator created" << std::endl;
return MX_SUCCESS;
}

REGISTER_OP(_custom_subgraph_op)
samskalicky marked this conversation as resolved.
Show resolved Hide resolved
.setParseAttrs(parseAttrs)
.setIsSubgraphOp()
.setCreateOpState(createOpState);

Expand Down Expand Up @@ -232,7 +218,8 @@ MXReturnValue mySupportedOps(std::string json,
}

MXReturnValue myAcceptSubgraph(std::string json, int subraph_id, bool* accept,
std::unordered_map<std::string, std::string>& options) {
std::unordered_map<std::string, std::string>& options,
std::unordered_map<std::string, std::string>& attrs) {
for (auto kv : options) {
std::cout << "option: " << kv.first << " ==> " << kv.second << std::endl;
}
Expand All @@ -243,6 +230,7 @@ MXReturnValue myAcceptSubgraph(std::string json, int subraph_id, bool* accept,
} else {
*accept = true;
std::cout << "accepting subgraph" << std::endl;
attrs["myKey"] = "myVal";
}
return MX_SUCCESS;
}
Expand Down
1 change: 1 addition & 0 deletions example/extensions/lib_subgraph/test_subgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
print('Testing partitioning with shapes/types')
arg_array = [mx.nd.ones((3,2),dtype='float32'), mx.nd.ones((3,2),dtype='float32')]
mysym2 = sym.optimize_for("myProp",arg_array)
print(mysym2.tojson())
exe2 = mysym2.bind(ctx=mx.cpu(), args={'a':mx.nd.ones((3,2)), 'b':mx.nd.ones((3,2))})
out2 = exe2.forward()
print(out2)
samskalicky marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
32 changes: 29 additions & 3 deletions include/mxnet/lib_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <map>
#include <unordered_map>
Expand Down Expand Up @@ -595,6 +596,7 @@ class CustomOp {
typedef MXReturnValue (*supportedOps_t)(std::string, int, int*,
std::unordered_map<std::string, std::string>&);
typedef MXReturnValue (*acceptSubgraph_t)(std::string, int, bool*,
std::unordered_map<std::string, std::string>&,
std::unordered_map<std::string, std::string>&);

/*!
Expand Down Expand Up @@ -777,7 +779,8 @@ typedef int (*partCallSupportedOps_t)(supportedOps_t, const char*, int, int *,
typedef int (*partCallAcceptSubgraph_t)(acceptSubgraph_t acceptSubgraph,
const char *json, int subgraph_id,
int *accept, const char* const*,
const char* const*, int);
const char* const*, int,
char***, char***, int*);

#define MXLIB_INITIALIZE_STR "initialize"
typedef int (*initialize_t)(int);
Expand Down Expand Up @@ -1142,16 +1145,39 @@ extern "C" {
#endif
_partCallAcceptSubgraph(acceptSubgraph_t acceptSubgraph, const char *json,
int subgraph_id, int *accept, const char* const* opt_keys,
const char* const* opt_vals, int num_opts) {
const char* const* opt_vals, int num_opts,
char*** attr_keys, char*** attr_vals, int *num_attrs) {
std::string subgraph_json(json);
bool accept_bool = false;
// create map of attributes from list
std::unordered_map<std::string, std::string> opts;
for (int i = 0; i < num_opts; i++) {
opts[std::string(opt_keys[i])] = std::string(opt_vals[i]);
}
MXReturnValue retval = acceptSubgraph(subgraph_json, subgraph_id, &accept_bool, opts);

//attributes to set on subgraph node
std::unordered_map<std::string, std::string> attrs;

MXReturnValue retval = acceptSubgraph(subgraph_json, subgraph_id, &accept_bool, opts, attrs);
*accept = accept_bool;

if (attrs.size() > 0) {
*num_attrs = attrs.size();
// allocate space for attributes
*attr_keys = static_cast<char**>(malloc (attrs.size() * sizeof(char*)));
*attr_vals = static_cast<char**>(malloc (attrs.size() * sizeof(char*)));

// copy attributes
int i=0;
for (auto kv : attrs) {
(*attr_keys)[i] = static_cast<char*>(malloc ((kv.first.size()+1) * sizeof(char)));
(*attr_vals)[i] = static_cast<char*>(malloc ((kv.second.size()+1) * sizeof(char)));
strcpy((*attr_keys)[i], kv.first.c_str());
strcpy((*attr_vals)[i], kv.second.c_str());
i++;
}
}

return retval;
}

Expand Down
14 changes: 8 additions & 6 deletions src/c_api/c_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ int MXLoadLib(const char *path) {
// set bool, dont pass bool across ABI boundary
isSubgraphOp = _isSubgraphOp;

CHECK(parse_fp != nullptr) << "Error loading '" << name
<< "' custom op, ParseAttrs function was not set.";
if (!isSubgraphOp) {
// validate custom operator functions from the dynamic library
CHECK(parse_fp != nullptr) << "Error loading '" << name
<< "' custom op, ParseAttrs function was not set.";
CHECK(fcomp_fp != nullptr || create_opstate_fp != nullptr) << "Error loading '" << name
<< "' custom op, Forward or CreateOpState function was not set.";
CHECK(type_fp != nullptr) << "Error loading '" << name
Expand Down Expand Up @@ -655,9 +655,6 @@ int MXLoadLib(const char *path) {
// check if operator is already registered
const nnvm::Op *regOpPtr = dmlc::Registry<nnvm::Op>::Get()->Find(name);
nnvm::Op &regOp = dmlc::Registry<nnvm::Op>::Get()->__REGISTER_OR_GET__(name);
regOp.set_attr_parser(attr_parser);
regOp.set_num_inputs(num_inputs);
regOp.set_num_outputs(num_outputs);
int plevel = 10;
if (regOpPtr != nullptr) {
// overwrite registration of existing op with custom op
Expand All @@ -667,6 +664,9 @@ int MXLoadLib(const char *path) {
plevel++;
}
if (!isSubgraphOp) {
regOp.set_attr_parser(attr_parser);
regOp.set_num_inputs(num_inputs);
regOp.set_num_outputs(num_outputs);
regOp.set_attr<nnvm::FInferType>("FInferType", infer_type, plevel);
regOp.set_attr<mxnet::FInferShape>("FInferShape", infer_shape, plevel);
regOp.set_attr<FInferStorageType>("FInferStorageType", infer_storage_type, plevel);
Expand All @@ -676,6 +676,8 @@ int MXLoadLib(const char *path) {
regOp.set_attr<nnvm::FMutateInputs>("FMutateInputs", mutate_inputs, plevel);
} else {
using namespace mxnet::op;
regOp.set_num_inputs(DefaultSubgraphOpNumInputs);
regOp.set_num_outputs(DefaultSubgraphOpNumOutputs);
regOp.set_attr<nnvm::FInferType>("FInferType",
DefaultSubgraphOpType, plevel);
regOp.set_attr<mxnet::FInferShape>("FInferShape",
Expand Down Expand Up @@ -765,7 +767,7 @@ int MXLoadLib(const char *path) {
mxnet::op::SubgraphBackendRegistry::Get()->__REGISTER_CUSTOM_PROPERTY__(name_str,
std::make_shared<mxnet::op::CustomSubgraphProperty>(
strategy_str, callSupportedOps, supportedOps_fp,
callAcceptSubgraph, acceptSubgraph_fp, op_name_str));
callAcceptSubgraph, acceptSubgraph_fp, callFree, op_name_str));
}
}
API_END();
Expand Down
20 changes: 18 additions & 2 deletions src/operator/subgraph/partitioner/custom_subgraph_property.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ class CustomSubgraphProperty: public SubgraphProperty {
supportedOps_t supportedOps,
partCallAcceptSubgraph_t callAcceptSubgraph,
acceptSubgraph_t acceptSubgraph,
opCallFree_t callFree,
std::string op_name) :
subgraphProp(subgraphProp_name),
callSupportedOps_(callSupportedOps),
supportedOps_(supportedOps),
callAcceptSubgraph_(callAcceptSubgraph),
acceptSubgraph_(acceptSubgraph),
callFree_(callFree),
subgraph_op_name(op_name) {}

// create custom subgraph property
Expand Down Expand Up @@ -162,6 +164,9 @@ class CustomSubgraphProperty: public SubgraphProperty {
virtual nnvm::NodePtr CreateSubgraphNode(const nnvm::Symbol &sym,
const int subgraph_id = 0) const {
int accept = 1;
int num_attr = 0;
char** attr_keys = nullptr;
char** attr_vals = nullptr;
if (acceptSubgraph_) {
nnvm::Graph g;
g.outputs = sym.outputs;
Expand All @@ -181,18 +186,28 @@ class CustomSubgraphProperty: public SubgraphProperty {
node->attrs.dict["isAux"] = "False";
}
}

samskalicky marked this conversation as resolved.
Show resolved Hide resolved
std::string subgraph_json = nnvm::pass::SaveJSON(g);
CHECK(callAcceptSubgraph_(acceptSubgraph_, subgraph_json.c_str(),
subgraph_id, &accept, opt_keys_.data(),
opt_vals_.data(), opt_keys_.size()))
opt_vals_.data(), opt_keys_.size(),
&attr_keys, &attr_vals, &num_attr))
<< "Error calling acceptSubgraph for '" << subgraphProp << "'";
}
if (accept) {
nnvm::NodePtr n = nnvm::Node::Create();
n->attrs.op = Op::Get(subgraph_op_name);
n->attrs.name = "_op" + std::to_string(subgraph_id);
n->attrs.subgraphs.push_back(std::make_shared<nnvm::Symbol>(sym));
// set user specified attributes
for (int i=0; i < num_attr; i++) {
n->attrs.dict[attr_keys[i]] = attr_vals[i];
callFree_(attr_vals[i]);
callFree_(attr_keys[i]);
}
// free memory used by custom op to allocate attributes
callFree_(attr_vals);
callFree_(attr_keys);
return n;
} else {
return NULL;
Expand All @@ -208,6 +223,7 @@ class CustomSubgraphProperty: public SubgraphProperty {
supportedOps_t supportedOps_;
partCallAcceptSubgraph_t callAcceptSubgraph_;
acceptSubgraph_t acceptSubgraph_;
opCallFree_t callFree_;
std::unordered_set<std::string> supportedNodes;
std::string subgraph_op_name;
std::vector<std::pair<std::string, std::string>> options_map_;
samskalicky marked this conversation as resolved.
Show resolved Hide resolved
Expand Down