fuse_reduce_mean: do not fuse when the scalar operand raises the rank - #2792
Open
LeSingh1 wants to merge 1 commit into
Open
fuse_reduce_mean: do not fuse when the scalar operand raises the rank#2792LeSingh1 wants to merge 1 commit into
LeSingh1 wants to merge 1 commit into
Conversation
fuse_reduce_mean validates the mul / real_div operand with
_check_var_scalar_value, which accepts any tensor whose size is 1 regardless of
its rank. A shape (1, 1, 1) const holding 1/count therefore passes, but the
mul broadcasts reduce_sum's output up to rank 3, and the reduce_mean that
replaces the pair does not:
@mb.program(input_specs=[mb.TensorSpec(shape=(2, 3))])
def prog(x):
s = mb.reduce_sum(x=x, axes=[1], keep_dims=False) # (2,)
return mb.mul(x=s, y=np.array([[[1.0 / 3]]], dtype=np.float32))
['reduce_sum', 'mul'] -> ['reduce_mean'], output shape (1, 1, 2) -> (2,)
The real_div branch has the same problem with a shape (1, 1, 1) count.
Check that the child op's output shape matches reduce_sum's output shape before
rewriting. A size-1 operand that does not raise the rank broadcasts to the same
shape and keeps fusing, so the pattern the pass targets is unaffected.
The check is local to this pass rather than in _check_var_scalar_value, which is
shared with several other passes.
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.
Problem
fuse_reduce_mean's docstring says the multiplier is aconst (scalar). The code validates it with_check_var_scalar_value, which accepts any tensor whosesize == 1, regardless of rank:A shape
(1, 1, 1)const holding1/counttherefore passes the check. Butmulbroadcastsreduce_sum's output up to rank 3, and thereduce_meanthat replaces the pair does not:The
real_divbranch has the same problem with a shape(1, 1, 1)count. Both are the model's declared output, so the converted model has a different output shape than the program it was built from.common::fuse_reduce_meanis in the default pipeline.Fix
Check that the child op's output shape matches
reduce_sum's output shape before rewriting. A size-1 operand that does not raise the rank (a plain scalar, or a shape(1,)const against a rank-1 reduce output) broadcasts to the same shape and keeps fusing, so the pattern the pass actually targets is unaffected.I deliberately put the check in this pass rather than tightening
_check_var_scalar_value, which is shared with several other passes that may legitimately want the looser size-1 test.Tests
In
TestReduceMeanFusion:test_invalid_pattern_rank_raising_mul— the repro above. Fails onmain.test_invalid_pattern_rank_raising_real_div— same through thereal_divbranch. Fails onmain.test_valid_pattern_size_one_tensor_multiplier— a shape(1,)multiplier that does not raise the rank must still fuse (guards against over-narrowing). Passes before and after.The existing
test_valid_pattern*/test_invalid_pattern*tests are untouched. I ran the whole class before and after; the failure sets are identical (this environment cannot load CoreML.framework, soassert_model_is_validfails there either way — the graph-structure assertions preceding it all run and pass).Note: this touches
test_cleanup_passes.py, which my PR #2786 also modifies, in a different class.