Repository navigation
deep-gemm: fused per-token FP8 cast in Triton (fused_per_token_cast_to_fp8), version 3 - #1326
IlyasMoutawwakil wants to merge 5 commits into
Conversation
…version 3 `deep_gemm.utils.per_token_cast_to_fp8` is upstream's PyTorch reference: about a dozen kernels, a zero-filled padded copy of the input, fp32 temporaries its size, and a host sync in the packed-UE8M0 check. This adds the same cast as one CUDA kernel, bit for bit (bfloat16 or float32 input, group 32 or 128, fp32 / UE8M0 / packed-UE8M0 scales), writing into caller-given outputs such as views of the Mega MoE symmetric buffer. It is compiled ahead of time in its own `[kernel.per_token_cast]` section, also for pre-Hopper archs, so it needs neither the JIT runtime nor a CUDA toolkit. A new function, hence version 3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This PR changes source code for the following kernel(s): If you have the kernel-bot build permissions, then trigger |
Same API and bit-exact output (60/60 cases against utils.per_token_cast_to_fp8 on B200), without a compiled extension. Writes straight into the given out/out_sf views. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| import kernels | ||
|
|
||
| deep_gemm = kernels.get_kernel("kernels-community/deep-gemm", version=2) | ||
| deep_gemm = kernels.get_kernel("kernels-community/deep-gemm", version=3) |
There was a problem hiding this comment.
quite a lot of this lol, wondering whether this can be simplified at some point using some helpers but not here
There was a problem hiding this comment.
agreed, a shared load_kernel() in the tests' conftest (or a VERSION constant) would make bumps one-liners. leaving it for a separate pr
There was a problem hiding this comment.
did it here after all: tests/generators.py loads the kernel once (the only get_kernel call), and every test file does from generators import deep_gemm, so the next bump is one line
There was a problem hiding this comment.
no per-file headers for local additions in this repo, only vendored upstream files keep theirs. it's covered by deep-gemm's LICENSE (DeepGEMM's MIT), and it reimplements their per_token_cast_to_fp8
| tl.store(sf_ptr + row * stride_sf + groups, scale, mask=group_mask) | ||
|
|
||
|
|
||
| def fused_per_token_cast_to_fp8(x, use_ue8m0, gran_k=128, use_packed_ue8m0=False, out=None, out_sf=None): |
There was a problem hiding this comment.
I assume this is essentially 1:1 to the deepgemm one but with slight adjustments
Lets shorten the docstrings to point that out + the main diff, no need to overcomplicate things
There was a problem hiding this comment.
yes, it's utils.per_token_cast_to_fp8 1:1 (bit-identical), the differences being one kernel and writing into out / out_sf. shortened the docstrings to say just that
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The version is pinned in one place, so a bump touches one line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds
deep_gemm.fused_per_token_cast_to_fp8, which does whatutils.per_token_cast_to_fp8does in one Triton kernel, with bit-identical output.utils.per_token_cast_to_fp8is upstream's PyTorch reference, used in its tests. transformers calls it on every DeepGEMM forward: the FP8/FP4 linear, both activations of the grouped experts, and Mega MoE. Each call costs:utils.per_token_cast_to_fp8fused_per_token_cast_to_fp8out/out_sf(e.g. views of the Mega MoE symmetric buffer, so no.copy_)use_ue8m0,gran_k,use_packed_ue8m0. Input is bfloat16 or float32. Optionalout/out_sfare added.torch-ext/deep_gemm/fused_cast.py). The vendored upstream sources are unchanged.tl.math.div_rn.tl.fdivlowers to the approximatediv.full.f32, and that is enough to move some values across an E4M3 rounding boundary.versiongoes to 3, and the tests load version 3.Results
Bit-identical to
utils.per_token_cast_to_fp8in all 60 cases checked on a B200:Timings are on a B200 with hidden 4096, bfloat16, group 32 and packed UE8M0 (the Mega MoE recipe):
utils.per_token_cast_to_fp8eagerTests
tests/test_kernels_ci.py(kernels_ci) checks two things:🤖 Generated with Claude Code