2525# fallback; we additionally surface a module-level flag and a hard guard.)
2626# * Added ``FusedLinearLogprobTriton`` autograd Function — a SkyRL-shaped
2727# adapter around verl's ``LinearCrossEntropy``/kernels that matches the
28- # pure-torch ``FusedLinearLogprob`` contract in ``model_utils.py`` exactly
29- # (see that class for the contract). This is NEW code, not from verl.
28+ # pure-torch ``FusedLinearChunkedDistributedLogprob`` contract in
29+ # ``model_utils.py`` exactly (see that class for the contract). This is NEW
30+ # code, not from verl.
3031#
3132# NOTE on the #2656 out-of-bounds-vocab fix: verl's forward mainloop masks
3233# out-of-bounds vocab columns to -inf for the LSE max/exp/denominator while
6869This module vendors verl's online-softmax fused linear-cross-entropy Triton
6970kernels (with the #2656 TP all-reduce / OOB-vocab masking scheme) and exposes
7071:class:`FusedLinearLogprobTriton`, an autograd Function that matches the exact
71- interface of the pure-torch ``FusedLinearLogprob `` in ``model_utils.py``.
72+ interface of the pure-torch ``FusedLinearChunkedDistributedLogprob `` in ``model_utils.py``.
7273
7374Triton/CUDA is required to actually *run* the kernel, but the module is import-safe
7475without triton (``TRITON_AVAILABLE`` will be ``False`` and the adapter raises a
@@ -1888,8 +1889,9 @@ def backward(ctx, dlogprobs: torch.Tensor, dentropy: torch.Tensor) -> list:
18881889
18891890
18901891# ======================================================================================
1891- # SkyRL adapter (NEW code — not from verl). Matches the pure-torch FusedLinearLogprob
1892- # contract in model_utils.py exactly so the two backends are interchangeable.
1892+ # SkyRL adapter (NEW code — not from verl). Matches the pure-torch
1893+ # FusedLinearChunkedDistributedLogprob contract in model_utils.py exactly so the two
1894+ # backends are interchangeable.
18931895# ======================================================================================
18941896
18951897# A label sentinel guaranteed to fall in NO shard's column range after re-keying. verl
@@ -1905,11 +1907,13 @@ def _verl_logprob_kernel_available() -> bool:
19051907class FusedLinearLogprobTriton (torch .autograd .Function ):
19061908 """Triton fused LM-head + vocab-parallel log-prob of the target token.
19071909
1908- Drop-in, interface-identical replacement for the pure-torch ``FusedLinearLogprob``
1909- in ``model_utils.py`` (same ``apply`` signature, same return/grad contract), backed by
1910- verl's online-softmax fused linear-cross-entropy Triton kernels (vendored above).
1910+ Drop-in, interface-identical replacement for the pure-torch
1911+ ``FusedLinearChunkedDistributedLogprob`` in ``model_utils.py`` (same ``apply`` signature, same
1912+ return/grad contract), backed by verl's online-softmax fused linear-cross-entropy Triton
1913+ kernels (vendored above). Selected via ``fused_lm_head_logprob_backend="triton"`` and dispatched
1914+ from ``model_utils._fused_lm_head_logprob_apply``.
19111915
1912- Contract (must match ``FusedLinearLogprob `` exactly):
1916+ Contract (must match ``FusedLinearChunkedDistributedLogprob `` exactly):
19131917 * ``apply(hidden, weight, target, vocab_start_index, vocab_end_index, chunk_size,
19141918 tp_group, inference_only=False) -> log_probs``.
19151919 * ``hidden``: ``[B, S, H]`` (TP-replicated / SP-already-gathered by the caller).
@@ -1942,7 +1946,7 @@ class FusedLinearLogprobTriton(torch.autograd.Function):
19421946 label-logit all-reduce. verl's epilogue would then return ``max + log(accu) - 0`` = the
19431947 LSE (garbage, not 0). We therefore force ``log_prob = 0`` for fully-OOV positions in
19441948 forward. We do NOT touch the backward gradient at those positions: the references (stock
1945- ``DistributedLogprob`` and the pure-torch ``FusedLinearLogprob ``) still emit
1949+ ``DistributedLogprob`` and the pure-torch ``FusedLinearChunkedDistributedLogprob ``) still emit
19461950 ``-softmax * grad_output`` there (the chosen-position term is absent because no shard owns
19471951 the column), and verl's kernel already reproduces that exact value for sentinel-keyed
19481952 labels. Zeroing the backward gradient at those positions would drop that term and diverge
@@ -1964,8 +1968,8 @@ def forward( # pyrefly: ignore[bad-override]
19641968 if not _verl_logprob_kernel_available ():
19651969 raise RuntimeError (
19661970 "FusedLinearLogprobTriton requires Triton (and a CUDA device), but triton is not "
1967- "importable. Install the optional 'triton' extra, or use the pure-torch "
1968- "FusedLinearLogprob backend instead."
1971+ "importable. Install the optional 'triton' extra, or use the default pure-torch "
1972+ "'torch' backend (FusedLinearChunkedDistributedLogprob) instead."
19691973 )
19701974
19711975 B , S , H = hidden .shape
@@ -1983,7 +1987,7 @@ def forward( # pyrefly: ignore[bad-override]
19831987
19841988 # hidden must be contiguous & 2D for the kernel. The kernel's ``tl.dot(hidden, weight.T)``
19851989 # requires BOTH operands to share a dtype, so cast hidden to the LM-head weight dtype here
1986- # — exactly what the pure-torch ``FusedLinearLogprob `` does (``hidden.to(weight.dtype) @
1990+ # — exactly what the pure-torch ``FusedLinearChunkedDistributedLogprob `` does (``hidden.to(weight.dtype) @
19871991 # weight.t()``) and what ``ColumnParallelLinear`` does before its bf16 GEMM. On a real
19881992 # hybrid model the pre-head hidden is fp32 (final norm) while the head is bf16, so without
19891993 # this the kernel asserts "Both operands must be same dtype. Got fp32 and bf16". When the
@@ -2047,7 +2051,7 @@ def backward(ctx: Any, *grad_outputs: torch.Tensor) -> tuple:
20472051 # would otherwise return the LSE there (no shard contributes the label logit). But the
20482052 # GRADIENT contract is set by the references this backend must match exactly — stock
20492053 # ``DistributedLogprob`` / ``ChunkedDistributedLogprob`` and the pure-torch
2050- # ``FusedLinearLogprob `` in model_utils.py. Those compute, for every position
2054+ # ``FusedLinearChunkedDistributedLogprob `` in model_utils.py. Those compute, for every position
20512055 # (in-shard, out-of-shard, or fully-OOV alike):
20522056 # d_logits = grad_output * (onehot(target) - softmax)
20532057 # and only ADD the ``onehot`` (chosen-position) term where the target is owned by this
0 commit comments