Skip to content

[NNVM][CONVOLUTION] Group convolution generalization for NHWC - #1232

Merged
tqchen merged 4 commits into
apache:masterfrom
srkreddy1238:tf
Jun 24, 2018
Merged

[NNVM][CONVOLUTION] Group convolution generalization for NHWC#1232
tqchen merged 4 commits into
apache:masterfrom
srkreddy1238:tf

Conversation

@srkreddy1238

Copy link
Copy Markdown
Contributor

No description provided.

@srkreddy1238
srkreddy1238force-pushed the tf branch 3 times, most recently from b0aed78 to 11738bfCompareJune 6, 2018 05:29
@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

@Huyuwei
Pls review.
This change due to different way of expecting the weights shape for NHWC and NCHW.
I have checked the compute definition of both depthwise and arrived at this.

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

If we are good with this, I will add a test case for NHWC-depthwise.

Comment threadnnvm/src/top/nn/convolution.cc Outdated
if (param.layout == "NHWC") {
wshape[kernel_layout.indexof('I')] *= param.groups;
} else {
wshape[0] *= param.groups;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

when param.layout == "NCHW", kernel_layout.indexof('I') = 0?

@srkreddy1238srkreddy1238Jun 10, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think wshape[kernel_layout.indexof('O')] *= param.groups can handle both cases
You can try some tests

@srkreddy1238srkreddy1238Jun 12, 2018

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

No it doesn't work this way as kernel layout for NCHW deviated from the format. (it's actually CNHW passed from frontend and same is expected in compute.).

Comment threadnnvm/src/top/nn/convolution.cc Outdated
if (param.layout == "NHWC") {
wshape[kernel_layout.indexof('I')] *= param.groups;
} else {
wshape[0] *= param.groups;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think wshape[kernel_layout.indexof('O')] *= param.groups can handle both cases
You can try some tests

Comment threadnnvm/src/top/nn/convolution.cc Outdated
wshape = ConvertLayout(wshape, kOIHW, kernel_layout);
wshape[0] *= param.groups;

// Depthwise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it's group convolution, and depthwise is just a special case

In fact, only depthwise convolution with multiplier=1 is supported now since it can be expressed as group convolution, see https://github.com/dmlc/tvm/blob/master/nnvm/python/nnvm/top/nn.py#L100-L101

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This generalisation works only if we pass kernel_layout as CNHW (IOHW).
IOHW is agreement between frontend and nchw_deptiwise_compute which infer shape doesn't know.
In my case also multiplier is 1.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Alternatively we could change frontend to pass kernel_layout as IOHW and generalise it to indexof('I') .

@Huyuwei

Copy link
Copy Markdown
Contributor

@srkreddy1238 Could you first add a test case that drives this change? It will help me better follow what's going on. You may need to modify these two files to test NHWC layout:
https://github.com/dmlc/tvm/blob/master/nnvm/python/nnvm/top/nn.py#L78
https://github.com/dmlc/tvm/blob/master/nnvm/tests/python/compiler/test_top_level2.py#L61

@srkreddy1238

srkreddy1238 commented Jun 13, 2018

Copy link
Copy Markdown
ContributorAuthor

@Huyuwei

We don't have a frontend with NHWC and depthwise now to give a clear test case. I could do this once we have tensorflow frontend.

Ref: https://github.com/srkreddy1238/tvm/tree/mobilenet
Head of this branch has the changes with tensorflow and mobilenet to demonstrate this change.

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

@Huyuwei

Test case added for NHWC, pls check.

@Huyuwei

Copy link
Copy Markdown
Contributor

My suggestion is we use wshape[kernel_layout.indexof('O')] *= param.groups to handle all layouts.

NHWC depthwise convolution can be expressed as

depthconv_nhwc=sym.conv2d(data, layout="NHWC", kernel_layout="HWOI")

while a normal grouped NHWC convolution can be expressed as

groupconv_nhwc=sym.conv2d(data, layout="NHWC", kernel_layout="HWIO")

The order of in_channel and out_channel in the kernel layout of topi.conv2d_nchw and topi.conv2d_nhwc is different, but the order of in_channel and multiplier in the kernel layout of topi.depthwise_conv2d_nchw and topi.depthwise_conv2d_nhwc is the same. It's better to deal with this asymmetry in frontend part, not c++ code.

@srkreddy1238 what do you think?

@Huyuwei

Copy link
Copy Markdown
Contributor

@srkreddy1238 May I ask one question? just for curiosity
Since convolution.cc is basically copied from mxnet source code, is there also a bug in grouped NHWC convolution is mxnet?
https://github.com/apache/incubator-mxnet/blob/master/src/operator/nn/convolution.cc#L152

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

", but the order of in_channel and multiplier in the kernel layout of topi.depthwise_conv2d_nchw and topi.depthwise_conv2d_nhwc is the same"

No, they are not same.

Let me check mxnet compute implementation..

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

@Huyuwei

Copy link
Copy Markdown
Contributor

@srkreddy1238 aha, thanks for the pointer.

In the kernel layout of both topi.depthwise_conv2d_nchw and topi.depthwise_conv2d_nhwc is, in_channel is before multiplier, is this right?
https://github.com/dmlc/tvm/blob/master/topi/python/topi/nn/depthwise_conv2d.py#L21-L22
https://github.com/dmlc/tvm/blob/master/topi/python/topi/nn/depthwise_conv2d.py#L76-L77

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

Yes, channel is before multiplier.

@Huyuwei

Copy link
Copy Markdown
Contributor

@srkreddy1238 For topi.conv2d_nchw, out_channel is before in_channel in kernel layout, while for topi.conv2d_nhwc, out_channel is after in_channel. And there is a mismatch between conv2d_nhwc and depthwise_conv2d_nhwc.

wshape[kernel_layout.indexof('O')] *= param.groups works for general group convolutions. Since group conv is not yet implemented in topi, now we dispatch depthwise conv to support a special case of group conv. To solve the kernel layout mismatch between conv2d_nhwc and depthwise_conv2d_nhwc, we need to specify kernel_layout="HWOI" for depthwise conv, which for general group conv is kernel_layout="HWIO" , as previously commented.

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

@Huyuwei

Thanks for the info. This makes clear to me.
I will work on modifications based on this.

@srkreddy1238srkreddy1238 changed the title [NNVM][CONVOLUTION] Generic index for group multiply - bug fix[NNVM][CONVOLUTION] Group comvolution generalization for NHWCJun 18, 2018
@srkreddy1238srkreddy1238 changed the title [NNVM][CONVOLUTION] Group comvolution generalization for NHWC[NNVM][CONVOLUTION] Group convolution generalization for NHWCJun 18, 2018
@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

@Huyuwei
Now works for both NCHW & NHWC. Pls review.

Comment threadnnvm/python/nnvm/top/nn.py Outdated
return topi.generic.schedule_depthwise_conv2d_nchw(outs)
elif groups == channels and layout == "NCHW":
return topi.generic.schedule_depthwise_conv2d_nchw(outs)
elif groups == channels and layout == "NHWC":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

elif groups == channels and layout == "NHWC" and kernel_layout == "HWOI":

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done.

Comment threadnnvm/python/nnvm/top/nn.py Outdated
@@ -98,9 +98,14 @@ def compute_conv2d(attrs, inputs, _):
if groups == 1:
out = topi.nn.conv2d(inputs[0], kernel, strides, padding, layout)
elif groups == get_const_int(inputs[0].shape[1]) and groups == channels:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add more checks here

eliflayout=="NCHW"andgroups==get_const_int(inputs[0].shape[1]) andgroups==channels:
out=eliflayout=="NHWC"andkernel_layout=="HWOI"andgroups==get_const_int(inputs[0].shape[3]) andgroups==channels:
out=

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done

Comment threadnnvm/python/nnvm/top/nn.py Outdated
elif layout == "NCHW" and \
groups == get_const_int(inputs[0].shape[1]) and \
groups == channels:
# NCHW

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

then this comment can be removed

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Handled

Comment threadnnvm/python/nnvm/top/nn.py Outdated
kernel_layout == "HWOI" and \
groups == get_const_int(inputs[0].shape[3]) and \
groups == channels:
# NHWC

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

and this line

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

handled.

@Huyuwei

Copy link
Copy Markdown
Contributor

@srkreddy1238 Can mobilenet be converted now? If so, add it to frontend tests.

@srkreddy1238

Copy link
Copy Markdown
ContributorAuthor

Ok. I will update frontend testcases with mobilenet this weekend.

@tqchen
tqchen merged commit 1e66d3c into apache:masterJun 24, 2018
@tqchen

Copy link
Copy Markdown
Member

This is merged as @Huyuwei approved the change. Please add mobilnet test in a separate PR

sergei-mironov pushed a commit to sergei-mironov/tvm that referenced this pull request Aug 8, 2018
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@srkreddy1238@Huyuwei@tqchen