Infer XNNPACK conv dimensionality from the weight rank - #21588
Open
adityasingh2400 wants to merge 1 commit into
Open
Infer XNNPACK conv dimensionality from the weight rank#21588adityasingh2400 wants to merge 1 commit into
adityasingh2400 wants to merge 1 commit into
Conversation
ATen lets stride, padding and dilation be a single value that is broadcast over every spatial dim, so len(stride) is not the conv dimensionality. A Conv2d built with stride=[2] was routed into Conv1dUnsqueezePass, which unsqueezed a 4d weight to 5d and failed in the fake tensor conv rule, and a Conv3d built with stride=[2] slipped past the partitioner guard that only supports 1d and 2d. Derive the dimensionality from the weight rank instead, and normalize stride and dilation in the conv2d node visitor the way padding and output_padding already are. Fixes pytorch#10965 Signed-off-by: Aditya Singh <adisin650@gmail.com>
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21588
Note: Links to docs will display an error until the docs builds have been completed. ❌ 1 Cancelled JobAs of commit 775b070 with merge base efd6b55 ( CANCELLED JOB - The following job was cancelled. Please retry:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
Contributor
|
Thanks for putting up the PR! Running CI now. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #10965.
ATen lets
stride,padding,dilationandoutput_paddingbe a single value that is broadcast over every spatial dim, solen(stride)is not the convolution's dimensionality.torch.nn.Conv2d(3, 3, 5, [2])keepsstride=(2,)because_pairpasses an iterable through unchanged, and that reaches the edge graph asaten.convolution.defaultwith a length-1 stride on a rank-4 weight.The XNNPACK backend infers dimensionality from that length in three places, so a 2d conv with a length-1 stride is mistaken for a 1d conv:
Conv1dUnsqueezePassskips a node unlesslen(stride) == 1, so it picked up the 2d conv, unsqueezed the already-4d weight to 5d and then failed inside the fake tensor convolution rule. That is the traceback in the issue.ConvolutionConfig.check_constraintsrejects 3d convs withlen(conv_stride) > 2. AConv3dbuilt withstride=[2]passes that guard, gets partitioned, and then hits the same unsqueeze path. The dynamic-quant guard right below it has the same problem in reverse: a genuine 2d conv with a length-1 stride is refused for no reason.Conv2d.define_nodealready normalizespaddingandoutput_paddingfrom length 1 to length 2, but notstrideordilation, socheck_or_raise(len(stride) == 2)fires anddilation[1]would be out of range. That is the second failure the issue describes, the one reached by addingdilation=[2].The fix takes the dimensionality from the weight rank, which is unambiguous, and normalizes
strideanddilationin the node visitor the same way the two neighbouring params already are._get_act_depsmoves to the same weight-rank derivation, which also stops a length-1paddingfrom making a 2d conv look 1d and silently blocking theconstant_pad_ndfusion.Review order:
_passes/conv1d_unsqueeze_pass.py, thenpartition/config/gemm_configs.py, thenoperators/op_conv2d.py, then the tests.Test plan
Added to
backends/xnnpack/test/ops/test_conv2d.py:test_fp32_conv2d_single_element_spatial_params, transposed and not, coveringstride=(2,)withpadding=(1,)test_fp32_conv2d_single_element_dilation, coveringdilation=(2,)test_fp32_conv3d_single_element_stride_doesnt_partition, asserting a 3d conv withstride=(2,)still produces zero delegatesI do not have an ExecuTorch C++ runtime built on this machine, so I could not run
run_method_and_compare_outputs, and the three tests above were not executed as unit tests. I verified the export and lowering half of them directly against this branch and againstupstream/mainat efd6b55, driving the same modules throughtorch.export.exportplusto_edge_transform_and_lower([XnnpackPartitioner()])and counting delegate and leftover convolution nodes.On
upstream/main:The conv3d row is the partitioner half of the bug. Today that conv is accepted by
ConvolutionConfigand then dies in the same pass, so the "Only support 1D + 2D Conv" guard is not actually holding.On this branch:
The conv1d and plain conv2d rows are there to show the unsqueeze path and the ordinary 2d path are untouched.
Because
Conv1dUnsqueezePassnow resolves the weight node before deciding, I also ran the same check throughXNNPACKQuantizerplusprepare_pt2eandconvert_pt2e, to exercise the dequant-unwrap branch. All four still fully delegate on this branch:And because
_get_act_depschanged how it decides 1d versus 2d, I re-ran the even-kernelsame-padding cases that exercise theconstant_pad_ndfusion. The pad and the conv are still both absorbed into one delegate:This PR was authored with AI assistance using Claude Code.
cc @GregoryComer @digantdesai @cbilgin @JakeStevens