-
Notifications
You must be signed in to change notification settings - Fork 749
[XNNPACK] Support 2d Transposed Convolution in XNNPACK delegate #7514
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
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/7514
Note: Links to docs will display an error until the docs builds have been completed. ✅ No FailuresAs of commit 731506f with merge base 3f9324c ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
Didn't find following labels among repository labels: release notes: Support 2d Transposed Convolution in XNNPACK delegate |
|
Didn't find following labels among repository labels: backends |
|
@pytorchbot label "release notes: backends" |
digantdesai
left a comment
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 brilliant. Thanks for adding this. This was on our list for a while. Great quality PR!
Added a few nits, and comments. I am happy with this, let's fix these and we can merge this.
In the meanwhile, let me run some more internal tests to make sure we are looking good.
Thanks again.
| self._test( | ||
| ConvTranspose2d(bias=has_bias), | ||
| quant_config=get_symmetric_quantization_config(), | ||
| check_quantized=False, # XNNPackQuantizer does not this pattern |
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.
hmm, we should be able to add support for it, here
| self._test(ConvTranspose2d(groups=2, in_channels=2, out_channels=6)) | ||
|
|
||
| def test_fp32_conv_transpose2d_bn(self): | ||
| class ConvTranspose2dBatchNorm(torch.nn.Module): |
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.
move this out or use the more complex version here?
| except: | ||
| torchao_installed = False | ||
|
|
||
| # Set higher recompile limit to avoid exception on over-recompilation in tests |
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.
How this is related to deconv? Just ran into this when running linear test?
| @@ -0,0 +1,430 @@ | |||
| # Copyright (c) Meta Platforms, Inc. and affiliates. | |||
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.
Thank you for adding these tests. I assume it was non-trivial to overload conv tests for transpose case?
| fp32_static_weights: XNN_FLAG_FP32_STATIC_WEIGHTS for fp16 conv | ||
| swap_in_out_for_transpose_weights: bool to indicate whether tensor shape should be | ||
| permuted and reshape from (inc, oc/groups, height, width) to (oc, inc/groups, height, width) | ||
| groups: number of groups for swap_in_out_for_transpose_weights |
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.
assert groups == 1 when the new flag is false.
| else: | ||
| assert f"Unsupported weight per channel quantization axis for depthwise conv2d: {quant_params.axis}, expecting 0." | ||
|
|
||
| if swap_in_out_for_transpose_weights and ( |
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.
Nit: can we cleanly merge with depthwise clause above, OK if it gets harder to read.
| kernel_shape = get_shape(kernel_node) | ||
| stride = cast(List[int], conv.args[3]) | ||
|
|
||
| if is_transpose and ( |
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.
Nit: Add a comment about kernel shape and strides matching
|
@digantdesai has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
| from typing import Optional | ||
|
|
||
| import executorch.extension.pybindings.portable_lib # noqa[F401] | ||
| import executorch.kernels.quantized # noqa[F401] |
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.
When doing local testing I am running into ModuleNotFoundError: No module named 'executorch.kernels'. I guess we need this to run the quantized ops when not lowered to XNNPACK. Can we skip running in the case of quantized graph and stop at serializing, perhaps that will eliminate the need to include this module?
5b1b565 to
26cd168
Compare
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.
@AkiSakurai Thank you for this contribution! This is super valuable, and appreciate the work put in to this, and this is the first external operator contribution from a user! Would love to hear some feedback on what it was like working in the code base. Any ways to improve our code quality, readability, documentation would all be great to hear.
-
What prompted the contribution? Personal feature enablement? Model enablement?
-
What part of the development flow took the longest setting up?
-
How easy was it to test and verify your code changes?
-
What part of the code was the hardest to navigate and the most confusing? Quantization? Passes? Schema Serialization?
-
What(if any) parts of the code were easy to navigate and understand?
| op_name = cast(torch._ops.OpOverload, node.target).name() | ||
|
|
||
| # Weight and Input should both be quantized | ||
| if op_name == exir_ops.edge.aten.convolution.default.name(): |
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.
what was the reasoning for this? I imagine it should've returned true in the previous implementation as well?
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.
The issue arises when a non-quantized operation is interleaved between two quantized operations. That operation also match the dequantize-op-quantize pattern. However, an operation with quantized input and float weight is not supported by XNNPACK.
| and weight_quant_params.per_channel | ||
| and (groups > 1 or weight_quant_params.axis != 1) | ||
| ): | ||
| why( |
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.
pretty neat way of checking this constraint
digantdesai
left a comment
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.
Thanks. The quantized import is no longer complaining.
|
@AkiSakurai I think you broke this test in a good way. Can you please fix it? 🙏 |
|
Once this is fixed, I can merge this. |
|
@digantdesai has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
* Support Transposed Convolution in XNNPACK delegate * Apply suggestions * Remove invalid restriction for transpose convolution batch normalization fusion * fix size analysis tool test
|
FYI #8090 |
Uh oh!
There was an error while loading. Please reload this page.