Skip to content

Fix XNNPACK rejecting avg_pool2d with default arguments - #21862

Open
slipstr34m wants to merge 1 commit into
pytorch:mainfrom
slipstr34m:fix-xnnpack-avgpool-default-cip
Open

Fix XNNPACK rejecting avg_pool2d with default arguments#21862
slipstr34m wants to merge 1 commit into
pytorch:mainfrom
slipstr34m:fix-xnnpack-avgpool-default-cip

Conversation

@slipstr34m

@slipstr34m slipstr34m commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Problem

AvgPoolingConfig.check_constraints rejects every node with count_include_pad=True:

if count_include_pad:
    why(
        node,
        reason="zero-padding in the averaging calculation is not supported",
    )
    return False

But count_include_pad=True is the aten default, so a plain nn.AvgPool2d(2) — the most common way to write the layer — never delegates to XNNPACK. The delegate splits around it and the node falls back to the portable op, and the WhyNoPartition log tells the user their model has zero-padding it does not have:

WhyNoPartition: Node aten_avg_pool2d_default was not partitioned because zero-padding in the averaging calculation is not supported.

The flag only has semantics when padded elements exist: it controls whether zeros from padding count toward the averaging divisor. With the default padding=0 there is nothing to include or exclude, so the rejection excludes nodes XNNPACK handles correctly. Verified numerically: with padding=0, eager outputs for count_include_pad=True and False are bit-identical, and the delegated result matches eager within ordinary float tolerance; with padding=1 they genuinely differ, which is the case the backend does not implement.

Fix

Reject count_include_pad=True only when the node has non-zero padding, reading padding from the existing normalize_pool2d_args call:

kernel_size, _, padding, _ = normalize_pool2d_args(node, has_dilation=False)
...
if count_include_pad and any(p != 0 for p in padding):

A no-op for every node the config currently accepts (those all have count_include_pad=False), and every currently-rejected padded node is still rejected, so the only behavior change is crash-to-delegate for the default-argument case. The visitor needs no change: it serializes the padding values themselves and never reads count_include_pad, and XNNPACK's divisor convention is irrelevant when no padded elements exist.

Effect

Same model, nn.AvgPool2d(2) with all-default arguments, through to_edge_transform_and_lower with the XNNPACK partitioner:

before: delegates=0  remaining aten.avg_pool2d.default in graph, WhyNoPartition blames zero-padding
after:  delegates=1  no avg_pool2d left in graph, output matches eager
guard:  padding=(1,1) with count_include_pad=True still not delegated

Testing

New test_fp32_avgpool2d_default_args lowers nn.AvgPool2d(2) end to end through serialize and compares outputs against eager. Verified failing-first: with the tests kept and only the source reverted, exactly that test fails and the other seven pass, including test_fp32_avgpool2d_count_include_pad_unsupported (padding=(1,1)), which still rejects under the fix.

backends/xnnpack/test/ops/test_avgpool2d.py: 7 -> 8 passed. Full backends/xnnpack/test/ops/ suite: 229 passed on main, 230 passed with this change, no regressions. The suite runs exclude test_prelu.py, whose test_fp32_prelu_constant_weight_empty_decompositions_file_load segfaults identically on unmodified main in my environment (prebuilt runtime, macOS arm64), so it cannot observe this change either way. lintrunner reports no issues on both changed files.

cc @GregoryComer @digantdesai @cbilgin @JakeStevens

AvgPoolingConfig rejected every node with count_include_pad=True, but that
is the aten default, so a plain nn.AvgPool2d(k) never delegated. The flag
only affects the averaging divisor when padded elements exist; with the
default zero padding there is nothing to include, so the rejection excluded
nodes XNNPACK handles correctly and its why-log blamed zero-padding the
node does not have.

The guard now rejects count_include_pad=True only when padding is non-zero,
which is the case the backend genuinely does not implement.
@pytorch-bot

pytorch-bot Bot commented Aug 15, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21862

Note: Links to docs will display an error until the docs builds have been completed.

✅ No Failures

As of commit ddb9251 with merge base ed65b12 (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 15, 2026
@slipstr34m

Copy link
Copy Markdown
Contributor Author

@pytorchbot label "release notes: none"

@pytorch-bot pytorch-bot Bot added the release notes: none Do not include this in the release notes label Aug 15, 2026
@JakeStevens JakeStevens added module: xnnpack Issues related to xnnpack delegation and the code under backends/xnnpack/ and removed release notes: none Do not include this in the release notes labels Aug 15, 2026
@JakeStevens
JakeStevens self-requested a review August 15, 2026 01:32
@github-actions

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. module: xnnpack Issues related to xnnpack delegation and the code under backends/xnnpack/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants