[Fix][Relax][Frontend][Torch] Make any and prod follow torch: missing overloads and result dtypes - #20376
[Fix][Relax][Frontend][Torch] Make any and prod follow torch: missing overloads and result dtypes#20376hiyufan wants to merge 1 commit into
Conversation
… overloads and result dtypes Two reductions were half-wired: - `any.default` (`x.any()`) had no converter. `any.dim` had one, but for anything other than a bool input it returned `max(x)` in the input dtype -- the largest value, not a truth value: `int32 [[0, 0, 5], [0, 0, 0]].any(1)` came back as int32 `[5, 0]` where torch gives bool `[True, False]`. torch.any asks whether any element is non-zero and is always bool. The converter now reduces the non-zero mask (`x != 0` for a non-bool input) with max in int8, since relax's max does not take bool, and casts back; `any.default` dispatches to it. - `prod.dim_int` (`x.prod(dim)`, with or without keepdim) had no converter, and `prod.default` kept the input dtype for a bool or integer input where torch accumulates in int64, exactly as `_sum` here already handles: `int32 [2^20, 2^20, 2] .prod()` overflowed to int32 where torch gives int64 2199023255552. `_prod` now applies the same rule as `_sum`, honours an explicit `dtype=`, treats an empty dim list as every axis, and serves both overloads. In the differential sweep of the frontend against torch.export (88 ops x 7 input shapes x static/dynamic), `any` goes from 14 raising programs to none and `prod` from 13 to one -- the 0-d input, which is a separate issue across all reductions. Tests: IR-level checks that `int32 x.prod(1)` casts to int64 before `R.prod` and that `int32 x.any(1)` lowers to not_equal -> int8 -> max -> bool; numeric checks of prod over every axis, one axis and keepdim (bool, int32 with an overflowing input, int64, float32), and of any in the same three forms over the same dtypes with an input whose second row is all zeros so both truth values appear. All six tests fail against the previous head. An explicit `dtype=` that already matches the input emits no cast, so `torch.prod(x, dtype=torch.float32)` on a float32 input still lowers to a bare `R.prod`, as `test_prod` in both frontend test files expects.
a0bc562 to
9cb5ff9
Compare
|
The first CI run went red on
I should say why my before/after check missed it: |
Problem
anyandprodwere each half-wired: one overload missing, and the overload that existed returning the wrong dtype (and, forany, the wrong value).mainx.any()Unsupported function types ['any.default']x.any(1)[[0, 0, 5], [0, 0, 0]][True, False][5, 0]x.any(0)x.prod(0)/x.prod(1, keepdim=True)Unsupported function types ['prod.dim_int']x.prod()[2²⁰, 2²⁰, 2]2199023255552x.prod()_anycomputedmax(x)and only cast back to bool for a bool input. For every other dtype it returned the maximum in the input dtype — the largest value, not "is any element non-zero". torch.any is always bool._prodhad no int64 accumulation for bool / integer inputs, which_sumin the same file already implements for the identical torch rule.Found by the same differential sweep as #20375; these were 27 of the 90 raising programs, plus the silent wrong-dtype rows above.
Fix
_any:x != 0for a non-bool input, cast the mask to int8 (relax'smaxdoes not take bool), reduce withmax, cast back to bool.any.defaultdispatches to it;any.dim/any.dimsunchanged in dispatch. Emptydimlist means every axis._prod: same int64 rule as_sumfor bool / integer inputs, honours an explicitdtype=, emptydimlist means every axis.prod.dim_intdispatches to it.Verification
Sweep:
anygoes from 14 raising programs to 0,prodfrom 13 to 1 (the 0-d()input — a separate issue across all reductions, out of scope).test_frontend_from_exported_program.pyandtest_frontend_from_fx.py: failure sets identical before and after apart from the new tests (test_prod[float32|bool]andtest_dtypes[*]fail identically onmainin my environment — a TVMScript parser issue with parametrised variables, not this change).ruff check/ruff format --check(v0.12.3) clean.Tests
test_prod_dim_and_integer_accumulation— IR-level:int32 x.prod(1)emitsastype int64thenR.prod(…, axis=[1]).test_prod_values—prod(),prod(0),prod(1, keepdim=True)over bool, int32 (overflowing input), int64, float32; dtype and values.test_any_returns_bool_for_every_dtype— IR-level forint32 x.any(1)(not_equal → astype int8 → max → astype bool); numericany(),any(1),any(0, keepdim=True)over bool, int32, int64, float32 with an input whose second row is all zeros so both truth values appear.All six fail against the previous head:
Independent of #20372 / #20373 / #20374 / #20375 (branched from
main).This change was prepared with AI assistance (Claude). I have reviewed and verified it, and can speak to it in review.