[ROCm][Bugfix] Enable the fp32 head_dtype torch.mm fast path on ROCm#48688
Open
wjabbour wants to merge 1 commit into
Open
[ROCm][Bugfix] Enable the fp32 head_dtype torch.mm fast path on ROCm#48688wjabbour wants to merge 1 commit into
wjabbour wants to merge 1 commit into
Conversation
Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Turner Jabbour <doubleujabbour@gmail.com>
noooop
approved these changes
Jul 15, 2026
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.
Purpose
#48390 added a
torch.mm(..., out_dtype=torch.float32)fast path so the fp32head_dtypelm_head projection avoids materializing a full fp32 copy of thelm_head weight on every step. That fast path was gated on
current_platform.is_cuda(), so ROCm always fell back to the cast path(
F.linear(hidden_states.to(fp32), lm_head.weight.to(fp32), ...)), whichallocates and writes a full fp32 copy of the (large) lm_head weight matrix
every forward step.
ROCm doesn't need that fallback. In PyTorch's
aten/src/ATen/native/cuda/Blas.cpp,the fp32-output/bf16-or-fp16-input case is handled on ROCm too — it's routed
to the classic (non-Lt)
hipblasGemmExpath instead of hipBLASLt (which has acorrectness bug for this exact dtype combination), not excluded outright:
This PR extends the fast-path gate to include ROCm.
Why this isn't a duplicate
Searched for related open/merged work (
head_dtype,out_dtype rocm,logits_processor rocm). Found two merged follow-ups to #48390 — #48525(LoRA path support) and #48654 (a ROCm CI test fix for an unrelated
CPU-dispatch issue in the same test file) — neither touches the
current_platform.is_cuda()gate in_apply_head.Test
torch.mm(bf16, bf16, out_dtype=torch.float32)produces correct,finite results on ROCm hardware (AMD Radeon RX 9070 XT, gfx1201, ROCm 7.1,
torch 2.13.0.dev) — matches an fp32 reference to ~1e-6.
test_fp32_head_uses_mm_fast_path_on_devicetotests/v1/sample/test_head_dtype.py, asserting the cast path (F.linear)is not called when the fast path is available, and that results match
the fp32 reference. Confirmed this test fails without the fix (falls
through to the cast path) and passes with it, on the RDNA4 hardware above.
pytest tests/v1/sample/test_head_dtype.py -k "not e2e": 6 passed.pre-commit run(ruff, mypy, etc.) on both changed files: passed.tests/v1/sample/is alreadymirrored onto AMD CI's MI250 (gfx90a) and MI300 (gfx942) runners (per
.buildkite/test-amd.yaml), so CI will validate this on CDNA hardware.call computes the fp32 projection, not the math — same as the cast path,
just without the extra fp32 weight materialization.
Notes
AI assistance (Claude Code) was used to investigate PyTorch's ROCm dispatch
behavior and draft this change; I reviewed every line and ran the tests above.