Add _grouped_mm dispatch handler to Float8Tensor - #4390
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/ao/4390
Note: Links to docs will display an error until the docs builds have been completed. ❗ 1 Active SEVsThere are 1 currently active SEVs. If your PR is affected, please view them below: ✅ No FailuresAs of commit 6cb1fd2 with merge base 8bbe1a5 ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
abb8ea6 to
8ff1b06
Compare
| def float8_grouped_mm(func, types, args, kwargs): | ||
| """Handles torch._grouped_mm when weight (mat_b) is a Float8Tensor. | ||
|
|
||
| If weight is RowWise-scaled, quantize activation and try |
There was a problem hiding this comment.
the code here should honor what the user specified in the config (either weight-only or dynamic quant), see _float8_addmm_impl in this file for an example
otherwise dequantize weight to bf16
we should not do this, as this silently changes what the user requested. If there is a path which is unsupported (for example, per-tensor quant), throw an exception.
| If weight is RowWise-scaled, quantize activation and try | ||
| F.scaled_grouped_mm; otherwise dequantize weight to bf16. | ||
| """ | ||
| from torch.nn.functional import ScalingType, scaled_grouped_mm |
There was a problem hiding this comment.
move to top of file, make sure to gate by the relevant pytorch version if needed
| assert isinstance(mat_b, Float8Tensor) | ||
| output_dtype = mat_a.dtype | ||
|
|
||
| # Detect transposed mat_b and check RowWise scaling |
There was a problem hiding this comment.
there should be no need to detect transposed here, the only syntax which we should support is grouped_mm(act, weight.transpose(-2, -1), ...)
|
high level approach looks good! I had some commments inline. Also, could you please rebase to get onto a revision with green CI. |
|
@claude review this PR |
|
Claude finished @vkuzo's task in 2m 15s —— View job PR Review: Add _grouped_mm dispatch handler to Float8Tensor
Overall the approach is sound and follows the established pattern from the NVFP4 Issues1. Import should be at module level (not inside function body)File: from torch.nn.functional import ScalingType, scaled_grouped_mmThis import is inside the function body. Per @vkuzo's comment, move it to the top of the file and gate it behind the relevant PyTorch version check (similar to how other version-gated imports work in this codebase). The 2. Non-RowWise path should raise an error, not silently dequantizeFile: # Non-RowWise: dequantize weight only
if not is_b_rowwise:
return torch._grouped_mm(mat_a, mat_b.dequantize(), offs=offs)As @vkuzo noted, silently dequantizing when the user configured a non-RowWise granularity (like PerTensor) changes the behavior without informing the user. The user expects quantized execution, but gets bf16 matmul instead. This should raise a This also means 3. Remove transpose detection logic — only support the canonical
|
…handling - Move ScalingType/scaled_grouped_mm import to top-level - Assert transposed only (remove if/else branching) - Use act_quant_kwargs.granularity for PerRow check (simpler than block_size un-swap) - Non-PerRow granularity raises NotImplementedError - Remove try/except fallback around scaled_grouped_mm - Weight-only path: dequantize weight only, no activation quantization - Add 'assert offs is not None' - Remove torch_version_at_least skip decorators from grouped_mm tests - Rename test to test_fp8_grouped_mm_non_rowwise_raises with assertRaises Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
db75fff to
04a1a6b
Compare
|
@claude Analyze the failure cases above. |
|
Claude finished @xiaowangintel's task in 2m 13s —— View job Analysis of CI Failure Cases
FindingsBoth failures are caused by the same root issue: a segmentation fault in an existing PT2E x86 inductor fusion test — NOT in your new CPU Nightly Failure
CUDA Nightly Failure
Key Observations
RecommendationThese failures are unrelated to your PR. As @vkuzo suggested, rebasing onto a newer main commit (once the nightly stabilizes or the upstream fix lands) should resolve this. You can verify by checking if the same tests fail on main without your changes. To confirm independently, you could also run just your new tests in isolation: pytest test/quantization/quantize_/workflows/float8/test_float8_tensor.py -k "grouped_mm" -v |
46c6f3e to
6692bdd
Compare
|
@vkuzo Your suggested changes have been incorporated. Please review them again. |
|
@claude review |
|
Claude finished @vkuzo's task in 5m 16s —— View job PR Review: Add _grouped_mm dispatch handler to Float8Tensor
The PR author has addressed the main feedback from the previous review. Here's my assessment of the current state: Previous Feedback — Status
The implementation is clean and follows the pattern from both Remaining Issues1. Granularity check uses activation granularity as a proxy for weight granularityFile: if not isinstance(act_quant_kwargs.granularity, PerRow):
raise NotImplementedError(...)This checks the activation granularity, relying on the fact that Consider adding an explicit check on the weight's block_size to be defensive: # After the act_quant_kwargs.granularity check, also verify weight is row-scaled
# mat_b is transposed, so its original block_size was [1, 1, K], now [1, K, 1]
assert mat_b.block_size[-1] == 1 and mat_b.block_size[-2] == mat_b.shape[-2], (
f"Expected row-wise scaled weight, got block_size={mat_b.block_size}"
)This is a minor/defensive point — the current code works correctly for all supported configs. 2. Missing version guard on
|
Summary
This PR adds an
aten._grouped_mm.defaultdispatch handler toFloat8Tensor, enabling FP8 inference for MoE (Mixture of Experts) models that usetorch._grouped_mmfor expert computation. This follows the same pattern established by NVFP4 in #4316.Motivation
MoE architectures (e.g., DeepSeek, Qwen3-MoE) store expert weights as 3D tensors
(E, N, K)and usetorch._grouped_mmin the forward pass. With this PR, users can quantize expert weights to FP8 viaquantize_()using existing configs (Float8WeightOnlyConfig,Float8DynamicActivationFloat8WeightConfig) and get automatic dispatch through the_grouped_mmhandler — no model code changes needed.Related: RFC #4355, NVFP4 reference #4316
Design
The handler supports two modes based on weight granularity:
RowWise-scaled weights (preferred path):
act_quant_kwargs(dynamic act+weight) orFloat8Tensor.from_hp()with PerRow (weight-only)F.scaled_grouped_mm(public API, backed byaten::_scaled_grouped_mm_v2)_grouped_mmNon-RowWise weights (PerTensor, PerGroup, etc.):
_grouped_mmwith bf16Test plan
3 test cases added to
TestFloat8Tensorintest_float8_tensor.py:test_fp8_grouped_mm_dynamic_act_weightFloat8DynamicActivationFloat8WeightConfigtest_fp8_grouped_mm_weight_onlyFloat8WeightOnlyConfigtest_fp8_grouped_mm_dequantize_roundtripFloat8WeightOnlyConfigParameterized over
(E, K, N)shapes. SQNR thresholds: weight ≥ 25, output ≥ 20.