Repository navigation
Arm backend: Fix ceil_mode pooling when the last window is dropped - #24893
Conversation
PyTorch drops a last ceil_mode pooling window that would start in the
right padding, so e.g. max_pool2d(kernel=2, stride=4, padding=0,
ceil_mode=True) on a width of 7 gives 2 output columns, the same as
floor mode. The input then has a remainder that no window uses.
SizeAdjustInputPass skipped every ceil_mode pool, so that remainder was
never sliced off and adjust_pooling_pad_if_needed returned a negative
post padding (-1 above). MAX_POOL2D and AVG_POOL2D were emitted with a
negative pad, which the TOSA reference model rejects ("At least one pad
is smaller than zero"). For avg_pool2d with count_include_pad=True,
DecomposeAvgPool2dPass fell back to padding with the full symmetric pad
instead, which made ceil_mode keep the dropped window and produced one
output element too many.
Slice the unused input for ceil_mode pools with static spatial shapes in
every dimension where ceil_mode does not add an output element, and do
not add post padding in DecomposeAvgPool2dPass when the needed post
padding is negative.
Test plan: Lowered 400 ceil_mode max_pool2d/avg_pool2d configurations
(kernel 1-3, stride 1-4, padding 0-1, count_include_pad, divisor_override,
input height 4-7) through TosaPipelineFP: 169 failed before, the
remaining 40 failures are all padding=0 with divisor_override, which is
a separate issue. Added test cases to test_max_pool.py and
test_avg_pool2d.py.
Signed-off-by: Eylon Eliyahu Krause <64223519+EylonKrause@users.noreply.github.com>
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24893
Note: Links to docs will display an error until the docs builds have been completed. ✅ No FailuresAs of commit 28af32a with merge base b3b565b ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
|
|
|
|
|
Thanks a lot for this PRs :) I kicked of some extended testing. As this is the first contribution to the project you will need to sign a EasyCLA, I hope that is OK, instructions are in a comment in this issue see #24893 (comment) :) |
Return a plain bool from _ceil_mode_adds_output (mypy: the comparison of two adjust_pooling_pad_if_needed results is typed bool | SymBool), and rewrap its docstring as docformatter expects. Signed-off-by: Eylon Eliyahu Krause <64223519+EylonKrause@users.noreply.github.com>
91dc013 to
4f22175
Compare
|
@pytorchbot label "release notes: arm" |
|
Thanks @zingo! I pushed a follow-up commit for the lintrunner findings: |
zingo
left a comment
There was a problem hiding this comment.
Thanks a lot for the fixes :) OK To merge! I'm not sure if you have access, if not let me know and I press the button :)
|
Don't think I have the authority yet, if you can do it yourself it would very much help, thanks :D |
|
MacOS fails are unrelated and probably fixed with #24903 Ill rebase and check |
…dding (#24894) ### Summary `DecomposeAvgPool2dPass` lowers `avg_pool2d` with a `divisor_override` to `avg_pool2d(count_include_pad=False)` on a zero padded input, followed by a multiplication by `kernel_size / divisor_override`. That is only exact when every window is full. `_compute_post_pad` returned early for `padding=0`, so with `ceil_mode=True` the last, partial window was averaged over its valid elements only. Example: `avg_pool2d(kernel=(1, 2), stride=(1, 2), padding=0, ceil_mode=True, divisor_override=2)` on `[1, 2, 3, 4, 5]`: PyTorch gives `[1.5, 3.5, 2.5]` (5 / 2), the decomposition gave `[1.5, 3.5, 5.0]`. This is a silent numerical error in the lowered model. This change computes the post padding for `ceil_mode` with a `divisor_override` also when `padding=0`, and inserts the pad whenever any pad value is non-zero rather than only when the symmetric pre-padding is. Behaviour only changes when `padding=0`, `ceil_mode=True` and `divisor_override` are all set. Independent of #24893 (it touches a different function in the same file; the two branches merge cleanly). Release notes: arm ### Test plan - New cases `divisor_override_ceil_mode_no_padding` and `divisor_override_ceil_mode_no_padding_count_include_pad` in `test_avg_pool2d.py`; they fail on main in the TOSA FP and INT variants and pass with this change. - Sweep over kernel 2-3, stride 1-3, padding 0-1, ceil_mode, count_include_pad, divisor_override in {None, 1, 2, 4, 7}, input height 4-15: 176 configurations with padding=0 fail on main (all with ceil_mode and a divisor_override), 0 with this change. - `test_avg_pool2d.py`, `test_decompose_avg_pool2d_pass.py`, `test_rewrite_avg_pool2d_pass.py`, `test_adaptive_avg_pool2d.py`, `test_mean_dim.py` (excluding u55/u85/vgf): no new failures. - Not run locally: the u55/u85/vgf variants (no Corstone FVP / Vela installed here), so those rely on CI. - `ufmt check` and flake8 clean on the changed files. Signed-off-by: Eylon Eliyahu Krause <64223519+EylonKrause@users.noreply.github.com>
|
Both merge! Super thanks and congratulation for you first contribution to the project! |
Summary
PyTorch drops a last
ceil_modepooling window that would start in the right padding, so e.g.max_pool2d(kernel=2, stride=4, padding=0, ceil_mode=True)on a width of 7 gives 2 output columns, the same as floor mode. The input then has a remainder that no window uses.SizeAdjustInputPassskipped everyceil_modepool, so that remainder was never sliced off andadjust_pooling_pad_if_neededreturned a negative post padding (-1 above). MAX_POOL2D and AVG_POOL2D were then emitted with a negative pad, which the TOSA reference model rejects ("At least one pad is smaller than zero"). Foravg_pool2dwithcount_include_pad=True,DecomposeAvgPool2dPassfell back to padding with the full symmetric pad instead, which kept the dropped window and produced one output element too many.This change:
ceil_modepools with static spatial shapes in every dimension whereceil_modedoes not add an output element (when the last window is dropped, the ceil and floor output sizes are equal, so the floor-mode slice is exact);DecomposeAvgPool2dPasswhen the needed post padding is negative.Dynamic (SymInt) spatial shapes keep the previous behaviour.
Release notes: arm
Test plan
ceil_mode_last_window_dropped/ceil_mode_last_window_dropped_paddingintest_max_pool.pyandceil_mode_last_window_dropped/ceil_mode_last_window_dropped_count_include_padintest_avg_pool2d.py. The TOSA FP/INT/INT a16w8 variants fail on main and pass with this change.ceil_modemax_pool2d/avg_pool2d configurations throughTosaPipelineFPand the TOSA reference model: 146/300 fail on main; the remaining 17 failures with this change are alldivisor_override+ceil_modevalue mismatches, a separate issue (separate PR). Floor mode: 200/200 pass before and after.pytest -c backends/arm/test/pytest.ini backends/arm/test/ops/test_max_pool.py backends/arm/test/ops/test_avg_pool2d.py backends/arm/test/passes(excluding u55/u85/vgf): no new failures.ufmt checkand flake8 clean on the changed files.cc @digantdesai @freddan80 @per @zingo @oscarandersson8218 @mansnils @Sebastian-Larsson @robell @rascani @nil-is-all