Skip to content

(fix: quantization) skip non-float module boundary values in graph mode - #173

Open
pkmandke wants to merge 4 commits into
apple:mainfrom
pkmandke:dev/skip_single_element_node_quant
Open

pkmandke wants to merge 4 commits into
apple:mainfrom
pkmandke:dev/skip_single_element_node_quant

Conversation

@pkmandke

@pkmandke pkmandke commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

tl;dr: module_input_spec={0: ...} on a decomposed SDPA module resolved to a SymInt from sym_size. prepare() then attached a FakeQuantize to a Python int and crashed on tensor.ndim. This fix skips non-float boundary values during prepare() in graph mode.


A module-level module_input_spec / module_output_spec that resolves to a
shape integer crashes prepare:

AttributeError: 'int' object has no attribute 'ndim'
  qparams_calculator.py:340  self._resolve_axis(tensor.ndim)

The prepared graph has activation_post_process_N(sym_size_int_M): a
FakeQuantize attached to a Python int.

Change/Fix

Skip non-floating-point values in _find_and_apply_module_level_spec (inputs and
outputs).

How it was found

module_input_spec={0: <fp8>} on a decomposed SDPA module, meant to quantize the
query. SDPA builds its causal mask from shape integers before touching the query,
so boundary input 0 ends up being a SymInt.

Tests

TestNonFloatModuleBoundary in test_graph_mode_quantizer.py, for the wildcard
and {0: spec} cases. Both fail before this change with the error above and
pass after.

Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
@pkmandke
pkmandke requested review from crowbat and vineet-g October 29, 2026 23:38
self._assert_state_observed(prepared_model, "linear_weight")


class TestNonFloatModuleBoundary:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can fold into TestSingleElementTensors next to test_single_element_module_boundary_not_observed. It uses the same model and config pattern. Broaden that class's docstring to "non-float or ≤1 element".

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also remove "matching eager mode" from the docstring. Such comments can get stale (if eager mode later changes behavior) and can be misleading..

)

fq_nodes = get_fake_quant_nodes(prepared_model)
assert fq_nodes, "Expected the float tensors to still be observed"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert fq_nodes always passes because the global config quantizes linear. Assert that the float boundary input y is observed instead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point!

I checked what gets observed and found that asserting y is observed would have the same problem since y is the linear output, which the global activation spec also observes in every case, so it passes with or without the module spec.

I changed the test so the assertion is meaningful instead:

  • The config no longer has a global part. It only sets module_input_spec on block, so y can only be observed through the module spec.
  • The test asserts that linear (y) is observed.
  • The indexed case is now {0: spec, 1: spec} instead of {0: spec}. With only index 0, y is boundary input 1 and is never selected, so the assert would fail.
  • The check that every observed node is a float tensor stays. It is what catches the original crash..

@pkmandke
pkmandke marked this pull request as ready for review November 2, 2026 23:41
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
@pkmandke
pkmandke requested a review from vineet-g November 3, 2026 01:11

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants