-
Notifications
You must be signed in to change notification settings - Fork 3
Compiling multiple-outputs nodes [Pre-WIP] #90
Conversation
multiple output nodes up to SGCompiler::CompileSubgraph refining the initial impl after discussion's w/ Matt fixing compile errors formatting tests1 fixing comp errors after rebase results in compute
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, yes, I think this is the right direction. There are some things to correct, as you mentioned, but I'm not seeing any major design flaws.
There's some code in create_layer_funcs and ParseNNVMGraph that deals with breaking "split", a multi-output mxnet op, into a number of smaller "split" ops. The emitter implementation of split is also based on breaking "split" down. We might be able to clean up the code if we can use this index idea instead, but that might also make the sgcompiler more complex.
@@ -29,6 +29,7 @@ class Emitter { | |||
Emitter(); | |||
// maps of ngraph operation generator functions | |||
OpEmitter ngraph_op_funcs_; | |||
std::map<NodePtr, NgraphNodePtr> op_map_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was an accident... Rebasing was very painful because I was modifying the same exact methods Louis moved out Graph
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch, yeah. Sorry.
if (!in_vec(subgraph_nodes, n)) | ||
for (auto i : n->inputs_) { | ||
if (in_vec(subgraph_nodes, i)) { | ||
if (!in_vec(outNodes, i)) { // TODO: use set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
order matters, we're preserving a topological sort here, don't use set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it could've worked for outNodes
since we are in complete control of a mapping process and we use these indices only after we are done editing outNodes
so the indices are relatively stable, but you are right I'd rather postpone testing this theory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point. Probably not worth fixing now, but good to keep in mind.
//@#$ FIX | ||
auto index = std::distance( | ||
begin(outNodes), | ||
std::find(begin(outNodes), end(outNodes), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is interesting. I would have just used a counter...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seemed more concise back then... I'll try counter when I get stn working
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's a problem, no need to change if you don't want to.
std::function<bool(NodePtr)> func) { | ||
auto subgraph_nodes = SelectNodes(node, func); | ||
std::pair<std::vector<NodePtr>, std::vector<NodePtr>> FindSubgraph( | ||
Graph &graph, NodePtr s, std::function<bool(NodePtr)> func) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We switched everything from s to node a while back to make the names a little clearer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will fix.
auto in_tmpGraphInputs = [&tmpGraph](NodePtr n) { | ||
auto in_tmpGraphInputs = [&tmpGraph]( | ||
NodePtr | ||
n) { //[nikolayk] 2nd time seeing this pattern why not use set? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
topological sort order
sub_graph->subgraph_outputs_.end(), results.begin(), | ||
[this](const NodePtr X) { return this->op_map_[X]; }); | ||
|
||
auto result = std::make_shared<ngraph::op::Tuple>(results); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't Core getting rid of Tuple? Will that cause issues here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will cross that bridge when we get there. As of now, we are free to use Tuple which in the near future will become XLATuple
which can continue to use until we ready to make a switch to GetOutputElement
for (size_t i = 0; i < subgraph->subgraph_outputs_.size(); i++) { | ||
nes.push_back(nnvm::NodeEntry{node, i, 0}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
auto osg = std::dynamic_pointer_cast<Graph>(n); | ||
auto index_of = | ||
[osg](nnvm::NodeEntry ne) -> int /*note, this returns an int*/ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:) I'm not sure the comment is needed
@@ -205,31 +218,41 @@ nnvm::Graph Compiler::Compile() { | |||
// register compiled subgraph with nnvm | |||
register_subgraph(sg); | |||
// create nnvm node | |||
auto sg_node = CreateNNVMNode(sg); | |||
auto sg_nodes = CreateNNVMNode(sg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sg_node_entries would be a little clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will change
} | ||
|
||
// TODO: [nikolayk] why don't we just walk | ||
// subgraph_outputs_[...]->orig_nodes_ and be done w/ the whole thing? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would probably work.
@@ -205,31 +218,41 @@ nnvm::Graph Compiler::Compile() { | |||
// register compiled subgraph with nnvm | |||
register_subgraph(sg); | |||
// create nnvm node | |||
auto sg_node = CreateNNVMNode(sg); | |||
auto sg_nodes = CreateNNVMNode(sg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will change
@@ -29,6 +29,7 @@ class Emitter { | |||
Emitter(); | |||
// maps of ngraph operation generator functions | |||
OpEmitter ngraph_op_funcs_; | |||
std::map<NodePtr, NgraphNodePtr> op_map_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was an accident... Rebasing was very painful because I was modifying the same exact methods Louis moved out Graph
if (!in_vec(subgraph_nodes, n)) | ||
for (auto i : n->inputs_) { | ||
if (in_vec(subgraph_nodes, i)) { | ||
if (!in_vec(outNodes, i)) { // TODO: use set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it could've worked for outNodes
since we are in complete control of a mapping process and we use these indices only after we are done editing outNodes
so the indices are relatively stable, but you are right I'd rather postpone testing this theory.
//@#$ FIX | ||
auto index = std::distance( | ||
begin(outNodes), | ||
std::find(begin(outNodes), end(outNodes), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seemed more concise back then... I'll try counter when I get stn working
std::function<bool(NodePtr)> func) { | ||
auto subgraph_nodes = SelectNodes(node, func); | ||
std::pair<std::vector<NodePtr>, std::vector<NodePtr>> FindSubgraph( | ||
Graph &graph, NodePtr s, std::function<bool(NodePtr)> func) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will fix.
if (pos != end(outNodes)) { | ||
outNodes.erase(pos); | ||
} | ||
i->subgraph_ = -1; // are any of these in outNodes should we |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the comment erasing works just fine
@@ -235,7 +225,8 @@ void CollapseSubgraphs(Graph &graph) { | |||
if (node->subgraph_ == i) tmpGraph->AddNode(node); | |||
|
|||
if (tmpGraph->nodes_.size() == 0) { | |||
// if we don't find any nodes, assume we've run out of subgraphs | |||
// if we don't find any nodes, assume we've run out of subgraphs TODO: | |||
// [nikolayk] how did we get there? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we might want to turn this into a for-loop
since we know the maximum number of sub graphs?
src/ngraph/ngraph_sgcompiler.cc
Outdated
@@ -49,39 +51,82 @@ void SGCompiler::CompileSubgraph(std::shared_ptr<Graph> sub_graph) { | |||
|
|||
// map the inputs into a parameter list | |||
// TODO: std::transform? | |||
ngraph::op::Parameters parameters; | |||
ngraph::op::Parameters forward_parameters; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to check the comments behind this change; I didn't realize forward_parameters
got renamed to parameters
.
sub_graph->subgraph_outputs_.end(), results.begin(), | ||
[this](const NodePtr X) { return this->op_map_[X]; }); | ||
|
||
auto result = std::make_shared<ngraph::op::Tuple>(results); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will cross that bridge when we get there. As of now, we are free to use Tuple which in the near future will become XLATuple
which can continue to use until we ready to make a switch to GetOutputElement
src/ngraph/ngraph_sgcompiler.cc
Outdated
|
||
f = std::make_shared<ngraph::Function>(result, result->get_value_type(), | ||
backward_parameters); | ||
////////////////////////////////////////////////////////////////////////////// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the scariest part.
No description provided.