You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
noop_elimination silently drops the floor of floor_div(x, 1) for float inputs #2761
The noop_elimination pass removes floor_div(x, y=1) as an identity, but floor_div rounds toward negative infinity, so floor_div(x, 1) == floor(x) != x for non-integer float inputs. The pass therefore silently drops the floor and changes the model's numerics — no error, just wrong results. noop_elimination is in the common (default) pipeline.
Reproduction
fromcoremltools.converters.mil.milimportBuilderasmbfromcoremltools.converters.mil.mil.passes.pass_registryimportPASS_REGISTRY@mb.program(input_specs=[mb.TensorSpec(shape=(4,))])defprog(x):
r=mb.floor_div(x=x, y=1.0)
returnmb.add(x=r, y=1.0)
PASS_REGISTRY["common::noop_elimination"].apply(prog)
print([op.op_typeforopinprog.functions["main"].operations])
# ['add'] -- floor_div silently removed; the model now computes x + 1 instead of floor(x) + 1
For x = [1.5, -0.5, 2.9, -2.1] the original graph computes floor(x) + 1 = [2, 0, 3, -1], but after the pass it computes x + 1 = [2.5, 0.5, 3.9, -1.1].
Cause
In noop_elimination.py, remove_elementwise groups floor_div with real_div and pow:
x / 1 == x and x ** 1 == x hold for all reals, but floor_div(x, 1) == floor(x) equals x only for integer x. floor_div is defined for fp16/fp32/i32 and there is no dtype guard, so the floor is dropped for float inputs.
Expected
floor_div(x, 1) should be removed only when x is integral, and kept for float inputs. PR incoming.
Activity