mirror of
https://github.com/deepseek-ai/DeepGEMM.git
synced 2026-11-05 00:47:26 +00:00
[GH-ISSUE #476] [Bug] SM90 fp8_einsum("bhr,hdr->bhd", a, b, d, c) silently drops c and returns a @ b.T #199
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
deepseek-ai/DeepGEMM#199
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @arxgy on GitHub (Oct 17, 2026).
Original GitHub issue: https://github.com/deepseek-ai/DeepGEMM/issues/476
Description
On SM90,
deep_gemm.fp8_einsum("bhr,hdr->bhd", a, b, d, c=c)returnsd = a \cdot b^\topinstead ofd = c + a \cdot b^\top. No error is raised, and the output looks like a normal result. The same happens whendandcare the same tensor (in-place accumulation). On SM100 the result is correct.The README's convention is
D = C + A @ B("fp8_gemm_ntwill do aD = C + A @ B.T"), andfp8_einsumacceptscon every architecture."bhr,hdr->bhd"is the onlyfp8_einsumexpression that runs on SM90, so any caller that accumulates through it on Hopper gets a wrong result.Environment
main1fc9c66, CUTLASS f3fde58, built with./develop.sh.Root Cause
The host prepares
dfor an accumulating kernel, but on SM90 it launches a kernel that only stores:fp8_einsumpassesctofp8_bmm(einsum.hpp L276), which callsgemm::early_return(L230). It copiescintod, expecting the kernel to add intod(gemm.hpp L49–L51):On SM90,
fp8_bmmcallssm90_fp8_bmm(einsum.hpp L247), which launchessm90_fp8_gemm_1d2d_impl. It setswith_accumulation = c.has_value()in theGemmDesc(sm90_fp8_gemm_1d2d.hpp L300), but the flag is not a template argument of the kernel (L36–L61), and the kernel writesDwith a plain TMA store (sm90_fp8_gemm_1d2d.cuh L434):This overwrites the
cthat step 1 copied intod. For comparison,sm90_bf16_gemmpasseswith_accumulationto its kernel askWithAccumulationand switches the store to a reduce-add.The other launcher of the same kernel,
sm90_fp8_gemm_1d2d(used byfp8_gemm_nt), rejectsc(sm90_fp8_gemm_1d2d.hpp L81):sm90_fp8_bmmhas no such check.tests/test_einsum.pypassesctofp8_einsumonly on SM100 (L183), so the SM90 path withcis untested.Reproduction
repro.py:Expected vs Actual
Expected:
d_out≈c + a @ b.T, with a relative error at the FP8 level. If SM90 does not supportchere, a host assertion is expected, as insm90_fp8_gemm_1d2d.Actual (
python repro.pyon the H100 above):d_outisa @ b.Tup to the FP8 error, andcis missing.Suggested Fix
Either of the following removes the silent wrong result. Which one fits the intended SM90 support?
Reject
cinsm90_fp8_bmm, assm90_fp8_gemm_1d2ddoes:With this change,
repro.pyraisesRuntimeError: Assertion error (csrc/apis/../jit_kernels/impls/sm90_fp8_gemm_1d2d.hpp:290): not c.has_value() and d.scalar_type() == torch::kBFloat16on the same H100. As insm90_fp8_gemm_1d2d, the check runs afterearly_returnhas copiedcintod.Support
con SM90: add an accumulation flag tosm90_fp8_gemm_1d2d_implthat writesDwith a TMA reduce-add, assm90_bf16_gemmdoes withkWithAccumulation, and passwith_accumulationto it fromsm90_fp8_bmm.I can open a PR for either option.