perf(ce): hardware exp2 (ex2.approx) for softmax#1266
Merged
Conversation
This was referenced Jun 25, 2026
Collaborator
|
Good find! Added a minor comment. @Tcc0403 @Mecoli1219 do you see any issues with this change? |
Collaborator
There was a problem hiding this comment.
We should define 1.4426950408889634 as a constant and use it instead of explicitly writing it multiple times.
Contributor
Author
There was a problem hiding this comment.
Changed it to a constant.
justinhh4
added a commit
to justinhh4/Liger-Kernel
that referenced
this pull request
Jun 25, 2026
Address review feedback on linkedin#1266: define 1.4426950408889634 once as the module-level LOG2_E constant and reference it from the three exp2 softmax sites instead of repeating the literal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address review feedback on linkedin#1266: define 1.4426950408889634 once as the module-level LOG2_E constant and reference it from the three exp2 softmax sites instead of repeating the literal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vaibhavjindal
approved these changes
Jun 26, 2026
Collaborator
|
A late review but should we have a wrapper to improve readability? @vaibhavjindal @Tcc0403 ?
|
Collaborator
|
I prefer plain exp2 call, leaving developers to decide ordering for numerical concerns. E.g. |
pull Bot
pushed a commit
to dumpmemory/Liger-Kernel
that referenced
this pull request
Jun 29, 2026
…inkedin#1275) Follow up to linkedin#1266 the cross entropy kernel reads the module level `LOG2_E` constant from inside the `@triton.jit` kernel. Newer Triton no longer allows accessing a plain (non-constexpr) global from within a kernel, so the kernel fails to compile with a NameError and the cross entropy correctness tests error out. Wrapping the constant in `tl.constexpr` is what the Triton error itself suggests, and it keeps the value identical. The cross entropy tests pass again with this change.
pull Bot
pushed a commit
to dumpmemory/Liger-Kernel
that referenced
this pull request
Jul 2, 2026
## CE `num_warps`: dtype- & arch-aware (Blackwell-gated) Rebased onto current `main` (post-linkedin#1266). All numbers below use **linkedin#1266 (`v1_exp2`) as the baseline**, so they isolate *this* PR's contribution and exclude linkedin#1266's exp2 gains. Measured on **B200**, which is what this gate targets. Correctness: full CE suite (bf16+fp32, with weight/softcap/label_smoothing/z_loss/ignore_index combos) passes. ### What & why Replace the hardcoded `num_warps=32` in CE forward with a dtype- and arch-aware choice: - **Blackwell (sm_100+) bf16/fp16 → 8**; everything else (Hopper & earlier, all fp32) → **32**; AMD → **16**. - Adds a small reusable helper `get_gpu_arch()` in `ops/utils.py` that returns `"blackwell"` / `"hopper"` / `"ampere"` / `""`. It uses `infer_device()` as the CUDA guard and excludes AMD via `is_hip()` (since `infer_device()` reports AMD as `"cuda"` too). The gate reads `get_gpu_arch() == "blackwell"`. - **Why 8 on Blackwell bf16:** CE there is *instruction-issue-bound* (ncu: ALU is the top pipe; the dominant stall is "Not Selected" from a surplus of warps) — fewer warps cut issue contention. Hopper/earlier and fp32 are *bandwidth-bound* and keep 32 to hide memory latency. - **Scoped to exactly bf16/fp16** (`element_size() == 2`) on sm_100+; fp8 (1 B) and fp32 keep 32 warps (unmeasured → safe default). `num_warps` is purely a scheduling parameter → no correctness impact. ### Headline (BT=8192, V=128256, full fwd+bwd; baseline = linkedin#1266) | dtype | baseline (linkedin#1266) | this PR | latency | throughput | |---|--:|--:|--:|--:| | bf16 | 1.686 ms | 1.438 ms | **−14.7%** | +17.2% | | fp32 | 1.892 ms | 1.892 ms | +0.0% (unchanged) | +0.0% | Only bf16/fp16 fires the gate; fp32 keeps 32 warps and is flat — shown to confirm no regression. ### bf16 across context length (V=128256; baseline = linkedin#1266) | BT | baseline | this PR | latency | |--:|--:|--:|--:| | 1024 | 0.405 ms | 0.391 ms | −3.4% | | 2048 | 0.583 ms | 0.542 ms | −7.0% | | 4096 | 0.950 ms | 0.839 ms | −11.6% | | 8192 | 1.686 ms | 1.438 ms | −14.7% | | 16384 | 3.184 ms | 2.694 ms | −15.4% | | 32768 | 6.092 ms | 5.101 ms | −16.3% | | 65536 | 11.958 ms | 9.924 ms | −17.0% | Gain grows with batch size (−3% → −17%; avg −12% over the sweep). ### bf16 across vocab (BT=8192; baseline = linkedin#1266) −17.1% @ V=32k → −8.6% @ V=262k (avg −13.0%) — larger relative win at smaller vocab. ### Figures <img width="818" height="566" alt="pr2_bf16_bt" src="https://github.com/user-attachments/assets/fda19ba4-aab2-4dbc-98de-8fc0ad060f7b" /> <img width="818" height="566" alt="pr2_bf16_vocab" src="https://github.com/user-attachments/assets/537b6af0-689c-4be0-97cd-f8b8c4953a08" /> <img width="818" height="566" alt="pr2_fp32_bt" src="https://github.com/user-attachments/assets/600c4e4f-c8b5-4791-a595-8bc5ea73419a" /> <img width="818" height="566" alt="pr2_fp32_vocab" src="https://github.com/user-attachments/assets/fc541ce2-1f62-44c4-9417-b0d039953299" /> --------- Co-authored-by: Justin Hu <181588904+justinhh4@users.noreply.github.com> Co-authored-by: Vaibhav Jindal <vaibhav.jndl@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
PR1: CE
exp2— B200 + H100 benchmarksOptimization measured against the frozen original baseline (
v0_base, == upstream HEAD). Correctness: full CE suite (177 cases, bf16+fp32, weight/softcap/smoothing/z_loss/ignore_index combos) passes.What & why
Replace
tl.expwith the hardwareex2.approxinstruction viae^x = 2^(x·log₂e), in both the online-softmax accumulation and the gradient pass.e^x—tl.explowers to a multi-instruction accurate sequence, whiletl.exp2emits a singleex2.approx.f32. This is the most frequent FP op in the kernel (once per vocab element × 2 passes), so it cuts total issued instructions.ex2.approxhas ~2.4e-7 relative error — within the suite's fp32rtol=1e-6and bf16rtol=5e-2, and softmax normalization further cancels the (correlated) error. Helps every dtype.Headline shape (BT=8192, V=128256, full fwd+bwd)
Across context length (V=128256, BT 1024–65536)
Figures
Latency vs context length and vs vocab, baseline vs this PR, on H100 and B200.