Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate fusion and Compilation #1564

Merged
merged 11 commits into from Aug 8, 2018
Merged

Separate fusion and Compilation #1564

merged 11 commits into from Aug 8, 2018

Conversation

zhiics
Copy link
Member

@zhiics zhiics commented Aug 7, 2018

This PR decouples fusion and compilation which has been discussed in the issue #1540.

Currently, lowering and fusion are implemented in the same pass. It would be more appropriate to make fusion and compilation as separate passes. This has the following benefits 1) fusion could be applied individually (even multiple times) in the future when necessary, 2) fusion could be target-independent while compilation (or lowering) is target-dependent.

In the future, we might need to make fusion more extendable so that different fusing rules could be applied in a more convenient manner.

This PR added graph_fuse.h to contain the fusion related structures and moved compilation related code to graph_compile.cc

@yzhliu
Copy link
Member

yzhliu commented Aug 7, 2018

@masahi Could you also help to do a review?

@yzhliu yzhliu self-assigned this Aug 7, 2018
@@ -299,7 +299,8 @@ def build(graph, target=None, shape=None, dtype="float32",
graph._set_json_attr("opt_level", 0, "int")
graph = graph.apply("InferShape").apply("InferType")
with target:
graph = graph.apply("GraphFusePartition").apply("GraphFuseCompile")
graph = graph.apply("GraphFusePartition").apply(
"GraphFuse").apply("GraphCompile")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest move

  graph = graph.apply("GraphFusePartition").apply(
                "GraphFuse")

to outside of with target above, as fusion should be target independent.

And separate it into two lines,

graph = graph.apply("GraphFusePartition")
graph = graph.apply("GraphFuse")

because in the future we want to add other fusion rules between "GraphFusePartition" and "GraphFuse".

I think "GraphFusePartition" should be renamed to something like "GraphFindFusibleGroups". It makes the separation of work between "Partition step" and "Fusion step" clearer. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point to move fusion out of target:)

I was also thinking a good name for GraphFusePartition as well. I was thinking of "GraphFusionSetup", because it basically sets up the vectors... Anyway, I think "GraphFindFusibleGroups" also works.

// The corresponding function.
GraphFunc compiled_func;
};

// Fuse the partitioned graph into segments.
// Create a new graph with fused noded.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noded -> nodes

// The corresponding function.
GraphFunc compiled_func;
};

// Fuse the partitioned graph into segments.
// Create a new graph with fused noded.
// Also inheritate attribute shape, dltype from previous graph.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inheritate -> inherit

// specially handle assign
const nnvm::Op* assign_op = nnvm::Op::Get("_assign");

std::vector<FuseEntry> fuse_vec(idx.num_nodes());
FuseVec fuse_vec(idx.num_nodes());
Copy link
Member

@masahi masahi Aug 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid confusion, rename fuse_vec to fuse_entries or something similar. The name 'fuse_vec' is also used in GraphFusePartition with a completely different type and sementics.

Copy link
Member

@masahi masahi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know some of the issues are left-over from the original code, but let's fix them this time.

const DTypeVector& dtype_vec = g.GetAttr<DTypeVector>("dtype");
const GroupVec& group_vec = g.GetAttr<GroupVec>("group_root");
const MasterVec &master_vec = g.GetAttr<MasterVec>("group_master");
const PatternVec &pattern_vec = g.GetAttr<PatternVec>("pattern");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put & after type name.

Copy link
Member Author

@zhiics zhiics Aug 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My clang format does this automatically. I will change the format-style...

// Start lowering
Array<tvm::LoweredFunc> func_list;
std::unordered_set<const tvm::Node*> func_set;
const IndexedGraph &idx = g.indexed_graph();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

& position

const auto& inode = idx[nid];
uint32_t new_nid = new_idx.node_id(kv.second.get());
if (inode.source->op() == assign_op) {
// Check if rhs of assign can be comute inplace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comute -> computed

} else {
assign_flag[new_nid] = 1;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix this weird } position.

// setup ref counter
nnvm::Graph GraphFuse(nnvm::Graph&& g) {
CHECK(g.HasAttr("group_root") && g.HasAttr("pattern"))
<< "GraphFusePartition pass hasn't been applied yet.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you rename "GraphFuseParition", make sure reflect that change here.

std::string target = g.GetAttr<std::string>("target");
std::string target_host;
const GroupVec& group_vec = g.GetAttr<GroupVec>("group_root");
const PatternVec &pattern_vec = g.GetAttr<PatternVec>("pattern");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

& position

const PatternVec &pattern_vec = g.GetAttr<PatternVec>("pattern");

CHECK(g.HasAttr("fused_entries")) << "Fusion hasn't been applied yet.";
FuseVec fuse_vec = g.MoveCopyAttr<FuseVec>("fused_entries");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename fuse_vec. See my comment at graph_fuse.cc

Copy link
Member

@masahi masahi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks for refactoring.

return g;
}

nnvm::Graph GraphCompile(nnvm::Graph g) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like can pass by const nnvm::Graph& g

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. The reason why I didn't pass const ref was because I was using MoveCopyAttr in the body. But anyway, passing by reference for a graph is better. I will change the body accordingly.

.set_body(GraphCompile)
.depend_graph_attr("shape")
.depend_graph_attr("dtype")
.depend_graph_attr("fused_entries")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to avoid plural form, use "fused_entry" instead

@yzhliu yzhliu merged commit 53d2431 into apache:master Aug 8, 2018
@yzhliu
Copy link
Member

yzhliu commented Aug 8, 2018

Thanks @zhiics and @masahi , this is now merged.
@tqchen Looks like the CI is encountering some unstable issue, sometimes openblas complains about too many thread created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants