qgallouedec HF Staff
Metrics return sums (num_correct_tokens, entropy_sum) instead of means
00e29bd verified |
Download README.md from trl-lib/fused-linear-ce: direct link, hf CLI and curl.
- Browser
- Download file 3.85 kB
-
https://huggingface.co/kernels/trl-lib/fused-linear-ce/resolve/v1/README.md
- Command line
-
hf download hf://trl-lib/fused-linear-ce@v1/README.md
-
curl -L -o README.md https://huggingface.co/kernels/trl-lib/fused-linear-ce/resolve/v1/README.md
3.85 kB
| library_name: kernels | |
| license: apache-2.0 | |
| tags: | |
| - kernel | |
| - triton | |
| - cross-entropy | |
| # fused-linear-ce | |
| A Triton **fused linear cross-entropy** kernel: it computes the cross-entropy of | |
| `hidden @ weight.T (+ bias)` against `targets` **without ever materialising the `(N, V)` logit | |
| matrix**. At a large vocabulary this turns the single most expensive step of LM training from a | |
| tens-of-gigabytes operation into a flat, small one. | |
| ## Usage | |
| ```python | |
| # pip install -U kernels | |
| from kernels import get_kernel | |
| flce = get_kernel("qgallouedec/fused-linear-ce", version=1, trust_remote_code=True) | |
| loss = flce.fused_linear_cross_entropy(hidden, lm_head.weight, labels) | |
| ``` | |
| Full signature: | |
| ```python | |
| fused_linear_cross_entropy( | |
| hidden, # (N, H) float32 / bfloat16 / float16 | |
| weight, # (V, H) same dtype as hidden | |
| targets, # (N,) int64 | |
| bias=None, # (V,) or None | |
| ignore_index=-100, | |
| logit_scale=1.0, | |
| softcap=None, | |
| reduction="mean", # "mean" | "sum" | "none" | |
| return_metrics=False, | |
| ) -> loss | (loss, {"num_correct_tokens": ..., "entropy_sum": ...}) | |
| ``` | |
| `hidden`, `weight` and `bias` all receive gradients. | |
| ### Metrics for free | |
| Trainers that switch to a fused loss normally lose their token-accuracy and entropy logging, | |
| because there are no logits left to compute them from. This kernel carries both through the same | |
| vocabulary sweep it already performs — the argmax rides along with the running row max, and the | |
| entropy term `sum_j p_j * logit_j` is accumulated with the same online rescaling as the | |
| log-sum-exp: | |
| ```python | |
| loss, metrics = fused_linear_cross_entropy(hidden, weight, targets, return_metrics=True) | |
| metrics["num_correct_tokens"] # int64 scalar, count of argmax == target | |
| metrics["entropy_sum"] # float32 scalar, summed softmax entropy in nats | |
| ``` | |
| **Both are sums over non-ignored positions, not means.** Sums are the more general contract: a | |
| per-rank mean cannot be recombined across distributed ranks holding different token counts, so a | |
| distributed trainer must gather sums before dividing, and the accuracy count stays an exact | |
| integer instead of a float that callers have to multiply back up. A single-process caller | |
| recovers the means by dividing by a count it already has: | |
| ```python | |
| n = (targets != -100).sum() | |
| mean_token_accuracy = metrics["num_correct_tokens"] / n | |
| mean_entropy = metrics["entropy_sum"] / n | |
| ``` | |
| Both are forward-only. `return_metrics=True` leaves the loss and the gradients **bit-identical** | |
| to `return_metrics=False`. | |
| ## Algorithm | |
| Implements the method described in | |
| [*Cut Your Losses in Large-Vocabulary Language Models*](https://huggingface.co/papers/2411.09009) | |
| (Wijmans et al., 2024). | |
| The forward pass tiles over the vocabulary. For each tile it computes the logit tile with `tl.dot` | |
| into an fp32 accumulator, applies bias / `logit_scale` / softcap, and merges the tile into a | |
| running log-sum-exp using the online-softmax rescaling that flash-attention uses. Nothing of size | |
| `(N, V)` is ever written. The backward pass **recomputes** each logit tile rather than storing it, | |
| forms `p - onehot`, and accumulates `grad_hidden = (p - onehot) @ weight` and | |
| `grad_weight = (p - onehot).T @ hidden`. Recomputation is cheaper than the memory traffic it | |
| avoids. | |
| ## Clean-room statement | |
| This is a **clean-room implementation**, written from the published algorithm and from the | |
| standard online-softmax formulation. It contains **no code derived from `apple/ml-cross-entropy`** | |
| or from any other implementation of the method. The upstream package was used only as a | |
| black-box numerical and performance oracle. Licensed **Apache-2.0**. | |
| ## Backends | |
| `build/torch-cuda` only. The sources are pure Triton and carry no CUDA-specific intrinsics, but | |
| ROCm and XPU builds are not shipped because they were not tested. | |