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

[Relay] Alter Op Layout #2150

Merged
merged 10 commits into from
Nov 30, 2018
Merged

Conversation

merrymercy
Copy link
Member

@merrymercy merrymercy commented Nov 21, 2018

Port alter_op_layout pass to relay. The new pass does forward rewrite in a single pass.

The major improvements over the old pass :

  • Enhance the layout inference for broadcast operators
    • The old pass doesn't change the layout for broadcast operators to fit conv2d. It kind of hacks the batch_norm and relies on the bias being an attribute of conv2d. However, we cannot do this on relay. The new pass will make the layout of broadcast operators to fit conv2d correctly.
  • Memorize transformations so we won't create duplicated transformations.

This pr also did some cleaning to operators.

cc @yzhliu @kevinthesun @tqchen

namespace tvm {
namespace relay {

class BiasAddSimplifier : public ExprMutator {
Copy link
Member

Choose a reason for hiding this comment

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

can we fold this into simplify inference?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. Because it is not only for inference.

@yzhliu
Copy link
Member

yzhliu commented Nov 22, 2018

will review tonight

* operator with other expressions.
*
* \param attrs The attribute of the node.
* \param inputs The arguments of this operator.
Copy link
Member

Choose a reason for hiding this comment

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

args & tinfos

// if the new layout changes width or height dimension,
// fallback to old layout;
input = raw_layout;
}
Copy link
Member

Choose a reason for hiding this comment

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

since you change the param instead, then these checker & fallback should be no use.
but I guess we need to modify pool compute to let it know how to deal with w & h.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, there is a small mistake here. I fixed that. In fallback case, we don't change the param.

// relay.layout_transform
std::pair<Layout, Layout> RemoveLeadingReduandantDimensions(
const Layout &src_layout, const Layout &dst_layout, size_t keep_size) {
// For a broadcast operator, if the input is a 3-dimensional tensor (64, 1, 1),
Copy link
Member

Choose a reason for hiding this comment

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

suggest to make it more clear, e.g., when broadcast (1, 64, 16, 16) with (64, 1, 1), we can still apply NCHW -> NCHW16c to the right tensor, by deleting N and applying normal CHW -> CHW16c layout transform. sth like that.

// we can still apply 4-dimensional rule NCHW -> NCHW16c to it.
// In this case, we will delete leading redundant dimensions.
CHECK_GE(src_layout.ndim(), keep_size)
<< "Can only apply layout transform rule for smaller tensor dimensions";
Copy link
Member

Choose a reason for hiding this comment

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

this error msg is not clear. suggest to print out src_layout and keep_size


// old_in, old_out = op.infer(old_in)
bool success = false;
std::tie(old_in, old_out, success) = CallInfer(ref_call, old_in);
Copy link
Member

Choose a reason for hiding this comment

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

try to learn, how does batch_flatten's FInferCorrectLayout gets registered?

Copy link
Member Author

@merrymercy merrymercy Nov 26, 2018

Choose a reason for hiding this comment

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

It is not defined. When we meet ops without FInferCorrectLayout such as batch_flatten. We will transform its inputs back to old layout.
https://github.com/merrymercy/tvm/blob/ad256f9d2fddf59c6c4224ab78be18437a13e6b2/src/relay/pass/alter_op_layout.cc#L99

lhs = rhs;
}

return Array<Array<Layout> > {{lhs, lhs}, {lhs}};
Copy link
Member

Choose a reason for hiding this comment

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

what if len(lhs) < len(rhs) ?

Copy link
Member Author

@merrymercy merrymercy Nov 26, 2018

Choose a reason for hiding this comment

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

I agree that more checks and good fallback should be considered here.
Will let you know when it's ready for review.

<< "cannot convert from " << param->src_layout << " to " << param->dst_layout;

std::tie(src_layout, dst_layout) = RemoveLeadingReduandantDimensions(
src_layout, dst_layout, inputs[0]->shape.size());
Copy link
Member

@yzhliu yzhliu Nov 23, 2018

Choose a reason for hiding this comment

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

RemoveLeadingReduandantDimensions has various checker, while it should still compile even though these restriction are not satisfied. e.g., broadcast(N16nCHW, CHW) -> broadcast(NCHW, CHW) will fail here, but actually we should be able to make it compile.

Also I'm a little worried about that, the approach allows layout and shape mismatch, and the mismatch is handled in layout_transform operator. In some sense, it's like other operators need to know how layout_transform works, then decide whether to infer a mismatch-shape layout. I would say, from the point view of system design, it's not quite good.

Also if later on there's another pass deal with layout, then it needs to carefully handle the mismatch stuff, and understand where does the mismatch come from.

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 points. I will clean this mismatch inside this pass.



def layout_transform(data, src_layout, dst_layout):
"""Transform the layout of an tensor
Copy link
Member

Choose a reason for hiding this comment

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

Should be Transform the layout of a tensor.

@tqchen
Copy link
Member

tqchen commented Nov 26, 2018

@merrymercy can you rebase the current PR, given the interest of this feature, it would be great to see if we can recover some of the end to end example benchmarks. #2163 should enable most of common networks already

@merrymercy
Copy link
Member Author

@tqchen Some operators (winograd, NCHWc) are still missing. Will do it in follow up prs.

@merrymercy merrymercy force-pushed the relay-alter-op-layout branch 2 times, most recently from ede6608 to 13338b9 Compare November 27, 2018 09:24
@merrymercy
Copy link
Member Author

merrymercy commented Nov 27, 2018

@yzhliu comments are addressed, please review again.
Now the layout transform for a broadcast operator is exactly "CHW" -> "CHW16c" rather than the old "NCHW" -> "NCHW16c".
The lhs-rhs length problem is fixed. Fallback mechanism is added.


# concatenate
@_reg.register_compute("concatenate")
def concatenate_compute(attrs, inputs, output_type, target):
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we also need a correct layout function for concatenate?

Copy link
Member Author

Choose a reason for hiding this comment

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

No. For concatenate, all its inputs will be transformed to old layouts. This is the default fallback case.

Copy link
Member

Choose a reason for hiding this comment

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

is it possible for concat to propagate layout?

Copy link
Member Author

@merrymercy merrymercy Nov 28, 2018

Choose a reason for hiding this comment

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

Yes. We should add it

const Array<Layout> &in_layouts,
const Array<Array<IndexExpr>> &in_shapes) {
const ConcatenateAttrs* param = attrs.as<ConcatenateAttrs>();
CHECK_EQ(in_layouts.size(), 2);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should allow more than two inputs?

Copy link
Member Author

@merrymercy merrymercy Nov 28, 2018

Choose a reason for hiding this comment

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

This is wrong. Not ready for review..

@merrymercy
Copy link
Member Author

@kevinthesun @tqchen please review again.

@@ -191,6 +191,23 @@ def simplify_inference(expr):
return _ir_pass.simplify_inference(expr)


def simplify_bias_add(expr):
Copy link
Member

Choose a reason for hiding this comment

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

Let us rename this to canonicalize_ops since bias_add lowering can be viewed as canonicalization step for ops, we might add more op canonicalizations later, (e.g. mean)..

TransformMemorizer() {}
explicit TransformMemorizer(NodePtr<Node> n) : NodeRef(n) {}

TransformMemorizerNode* operator->() {
Copy link
Member

Choose a reason for hiding this comment

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

You can just mark TransformMemorizerNode* operator->() const, to allow it to be accessed by the const

Copy link
Member Author

Choose a reason for hiding this comment

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

But I need to modify the content?


// Make a transform CallNode
Expr TransformLayout(Expr raw, Layout src_layout, Layout dst_layout) {
if (src_layout.Equals(dst_layout))
Copy link
Member

Choose a reason for hiding this comment

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

either keep the return in the single line, or enclose with { }

}

// Memorize layout transform so we can reuse internal transformed nodes
class TransformMemorizerNode : public Node {
Copy link
Member

Choose a reason for hiding this comment

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

expand the comment a bit. what is the key of the map, what is the content

using TransformKey = std::tuple<const Node*, std::string, std::string>;
struct key_hash : public std::unary_function<TransformKey , std::size_t> {
std::size_t operator()(const TransformKey& k) const {
return std::hash<const Node*>()(std::get<0>(k)) ^
Copy link
Member

Choose a reason for hiding this comment

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

use dmlc::CombineHash

return static_cast<TransformMemorizerNode*>(node_.get());
}

// Transform layout with memorizer
Copy link
Member

Choose a reason for hiding this comment

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

document all the arguments and return value

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the rule is functions in header files should be documented while functions in src files are not required to doc thoroughly, is it true?

Copy link
Member

Choose a reason for hiding this comment

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

that is true, but it is still helpful to document some of them to make code more readable

// Transform layout with memorizer
Expr Transform(Expr raw, const Layout& src_layout, const Layout& dst_layout) {
if (src_layout.Equals(dst_layout))
return raw;
Copy link
Member

Choose a reason for hiding this comment

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

keep raw in the same line as if


// Call FInferCorrectLayout of an op.
// Return inferred_input_layout, inferred_output_layout, success
std::tuple<Array<Layout>, Array<Layout>, bool> CallInfer(
Copy link
Member

Choose a reason for hiding this comment

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

document the fields of the return value and the arguments

const NodeRef& ctx) {
std::vector<LayoutAlternatedExpr> inputs;
std::vector<Expr> normal_new_args;
Array<Array<IndexExpr>> input_shapes;
Copy link
Member

Choose a reason for hiding this comment

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

space between > for compatibility to old compilers

// NOTE: discard the "const" qualifier
TransformMemorizer memorizer = Downcast<TransformMemorizer>(ctx);

// fill incomplete state and expand tuple
Copy link
Member

Choose a reason for hiding this comment

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

Explain that we always expect LayoutAlternatedExpr, and this is used to convert the arguments into LayoutAlternatedExpr.

@tqchen
Copy link
Member

tqchen commented Nov 28, 2018

@yzhliu @jroesch @kevinthesun @ajtulloch can you please take a look at this PR if you have time?

@merrymercy merrymercy force-pushed the relay-alter-op-layout branch 2 times, most recently from 45f0754 to 8f9e396 Compare November 29, 2018 02:25
@merrymercy
Copy link
Member Author

comments are addressed!

Copy link
Member

@yzhliu yzhliu left a comment

Choose a reason for hiding this comment

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

good to me. ping @jroesch

@tqchen
Copy link
Member

tqchen commented Nov 29, 2018

@merrymercy please rebase against the latest master

@merrymercy merrymercy merged commit 2a5656b into apache:master Nov 30, 2018
@merrymercy merrymercy deleted the relay-alter-op-layout branch November 30, 2018 01:13
@srkreddy1238
Copy link
Contributor

Not sure if I am the only one see this issue in local build.
** submodule update is also done.

[ 52%] Building CXX object CMakeFiles/tvm.dir/src/relay/op/nn/convolution.cc.o
In file included from /home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/../op_common.h:14:0,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/resize.cc:11:
/home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/../../pass/alter_op_layout.h: In function ‘tvm::Array<tvm::Array<tvm::relay::Layout> > tvm::relay::ElemwiseArbitraryLayout(const tvm::Attrs&, const tvm::Array<tvm::relay::Layout>&, const tvm::Array<tvm::relay::Layout>&, const tvm::Array<tvm::Array<HalideIR::Expr> >&)’:
/home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/../../pass/alter_op_layout.h:55:72: error: no matching function for call to ‘tvm::Array<tvm::relay::Layout>::Array(size_t, tvm::relay::Layout&)’
   return Array<Array<Layout> >{Array<Layout>(old_in_layouts.size(), ret), {ret}};
                                                                        ^
In file included from /home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/ir/Expr.h:10:0,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/include/tvm/expr.h:9,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/include/tvm/packed_func_ext.h:17,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/include/tvm/api_registry.h:12,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/include/tvm/relay/base.h:9,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/include/tvm/relay/op.h:16,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/resize.cc:6:
/home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/tvm/node/container.h:180:3: note: candidate: tvm::Array<T, <template-parameter-1-2> >::Array(const std::vector<T>&) [with T = tvm::relay::Layout; <template-parameter-1-2> = void]
   Array(const std::vector<T>& init) { // NOLINT(*)
   ^~~~~
/home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/tvm/node/container.h:180:3: note:   candidate expects 1 argument, 2 provided
/home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/tvm/node/container.h:173:3: note: candidate: tvm::Array<T, <template-parameter-1-2> >::Array(std::initializer_list<_Tp>) [with T = tvm::relay::Layout; <template-parameter-1-2> = void]
   Array(std::initializer_list<T> init) { // NOLINT(*)
   ^~~~~
/home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/tvm/node/container.h:173:3: note:   candidate expects 1 argument, 2 provided
/home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/tvm/node/container.h:166:3: note: candidate: template<class IterType> tvm::Array<T, <template-parameter-1-2> >::Array(IterType, IterType)
   Array(IterType begin, IterType end) {
   ^~~~~
/home/srk/work/NN/TF-DMLC/relay/tvm/3rdparty/HalideIR/src/tvm/node/container.h:166:3: note:   template argument deduction/substitution failed:
In file included from /home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/../op_common.h:14:0,
                 from /home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/resize.cc:11:
/home/srk/work/NN/TF-DMLC/relay/tvm/src/relay/op/image/../../pass/alter_op_layout.h:55:72: note:   deduced conflicting types for parameter ‘IterType’ (‘long unsigned int’ and ‘tvm::relay::Layout’)
   return Array<Array<Layout> >{Array<Layout>(old_in_layouts.size(), ret), {ret}};

@srkreddy1238
Copy link
Contributor

Ignore above issue. looks like submodule update didn't sync all changes.

FrozenGene pushed a commit to FrozenGene/tvm that referenced this pull request Dec 27, 2018
* [RELAY] Finish alter op pass

* [RELAY] AlterOpLayout Pass

* fix broadcast operators

* fix broadcast operators

* fix broadcast operators

* Support concatenate

* address comments

* address comments

* add comments

* rebase
@ZihengJiang ZihengJiang mentioned this pull request Feb 1, 2019
wweic pushed a commit to neo-ai/tvm that referenced this pull request Feb 20, 2019
* [RELAY] Finish alter op pass

* [RELAY] AlterOpLayout Pass

* fix broadcast operators

* fix broadcast operators

* fix broadcast operators

* Support concatenate

* address comments

* address comments

* add comments

* rebase
wweic pushed a commit to neo-ai/tvm that referenced this pull request Feb 20, 2019
* [RELAY] Finish alter op pass

* [RELAY] AlterOpLayout Pass

* fix broadcast operators

* fix broadcast operators

* fix broadcast operators

* Support concatenate

* address comments

* address comments

* add comments

* rebase
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.

6 participants