Repository navigation
Conversation
The torch fused log-prob op divided the BF16 output weight by the temperature before the projection, which rounds W/T to BF16 and gives different log-probs, gradients and entropy than the unfused path, which divides the FP32 logits. Divide each FP32 chunk of logits instead, and apply the 1/T factor to the FP32 logit gradient before casting it. The Triton backend still receives weight / temperature. Signed-off-by: Corey Hu <corey.hu@scale.com>
There was a problem hiding this comment.
Code Review
This pull request updates the temperature scaling logic in the fused LM-head logprob calculation. Instead of scaling the weights before projection, the torch backend now scales the FP32 logits directly after projection, matching the order of operations in the unfused path. The backward pass is updated accordingly to apply the temperature factor to the logit gradients. Additionally, a comprehensive CPU test suite has been added to verify that the fused log-probs, gradients, and entropy metrics match the unfused reference implementation. I have no feedback to provide as there are no review comments.
|
Summary
With
temperature != 1, the torch fused LM-head path (FusedLinearChunkedDistributedLogproband the fused entropy metric) divided the BF16 output weight by the temperature before the projection. This PR divides each FP32 chunk of logits instead, and applies1/Tto the FP32 logit gradient before casting it, the same order as the unfused path (logits.float() / T). The Triton backend still receivesweight / temperature; its kernel already takes a temperature, but switching it needs GPU validation.Why
W / Tis rounded to BF16, so fused log-probs, gradients and entropy drift from the unfused path. The docstring said the two were numerically identical.Testing
tests/backends/skyrl_train/distributed/test_fused_lm_head_temperature.py(BF16, T=0.7): fused log-probs and hidden grads now match the unfused path exactly. All 3 cases fail on main (log-prob error 4.2e-2, entropy 2.0e-2).pytest tests/backends/skyrl_train/distributed/: 196 passed, 15 skipped (main: 193, 15). CPU suite (tests/train/ tests/backends/skyrl_train/,-m "not vllm"): 2225 passed, 41 skipped (main: 2222); the same 2 Megatron import failures occur on main. pre-commit clean.This conflicts textually with #2374, which edits the same op.
AI assistance: Claude Code ported this from our patch set, wrote the tests, and drafted this description.
Note
Medium Risk
Changes numerics and autograd for fused log-prob/entropy used in Megatron RL training when temperature ≠ 1; Triton path is untouched.
Overview
Aligns torch fused LM-head temperature scaling with the unfused path by scaling FP32 logits after projection instead of dividing BF16 weights before the matmul.
FusedLinearChunkedDistributedLogprobnow takes atemperatureargument: forward divides each chunked FP32 logits tensor byT; backward applies1/Tto the FP32 logit gradient before projecting to hidden/weight grads. Callers (from_parallel_hidden_to_logprobs, packed variant,_fused_vocab_parallel_entropy_from_hidden) no longer mutatelm_head_weight; they passtemperaturethrough_fused_lm_head_logprob_apply. The Triton backend is unchanged and still receivesweight / temperature.Adds CPU tests (
test_fused_lm_head_temperature.py) that fused log-probs, gradients, and entropy match the referencematmul → float32 → /Tbehavior atT=0.7with BF16 weights (chunked and single-chunk).Reviewed by Cursor Bugbot for commit b7d0da6. Bugbot is set up for automated code reviews on this repo. Configure here.