[Perf] Use direct FLCE weight-gradient accumulation for FP16, BF16, and FP32 - #1324
[Perf] Use direct FLCE weight-gradient accumulation for FP16, BF16, and FP32#1324Anubhav-2003 wants to merge 1 commit into
Conversation
f6d302d to
7968bec
Compare
| grad_weight, | ||
| grad_logits_t, | ||
| input_chunk, | ||
| out_dtype=torch.float32, |
There was a problem hiding this comment.
wouldn't it be more straightforward to set out_dtype=grad_weight.dtype? with a little bit change on branching condition.
There was a problem hiding this comment.
Thank you very much for the review. I see how that would simplify the path for PyTorch ≥2.8. Since Liger supports PyTorch ≥2.1.2, using out_dtype for all these cases would either require retaining a separate path for older versions or leave them on the allocating fallback. That’s why I kept addmm_ for same-dtype accumulation. Would you prefer limiting this optimization to PyTorch ≥2.8 instead? But then older versions will keep using the unoptimized path.
There was a problem hiding this comment.
yes, modify output_dtype in 2.8+ path.
add_ supports mismatching dtype but I don't recall which version starts supporting it. We can change the other path to grad_weight.add_(torch.mm(grad_logits_chunk.t(), _input_chunk)) if 2.1.2 has it covered
There was a problem hiding this comment.
Thank you for the clarification. I checked PyTorch 2.1.2, and add_ supports the floating-point dtype conversions needed here. I’ll use out_dtype=grad_weight.dtype for the eligible 2.8+ path and grad_weight.add_(torch.mm(...)) as the fallback, with coverage for both paths.
d379190 to
f5255b8
Compare
Accumulate same-dtype FP16, BF16, and FP32 chunk gradients directly into grad_weight on supported NVIDIA CUDA devices. This removes avoidable full-size intermediates while preserving the mixed-precision FP32 path and other fallbacks, and adds direct-path regression coverage.
f5255b8 to
9fe6f57
Compare
|
@Tcc0403 I have made the changes as per your advice. You may take a look whenever you are free. Thank You. |
Summary
This PR reduces allocation and memory-traffic overhead in Liger fused linear cross entropy by accumulating same-dtype FP16, BF16, and FP32 weight-gradient contributions directly into the existing
grad_weightbuffer on supported NVIDIA CUDA devices.The broader goal is to keep Liger FLCE competitive with PyTorch 2.13 native
linear_cross_entropyacross the dtypes used for training. Both implementations avoid retaining a full[tokens, vocabulary]logits tensor, but Liger's fallback weight-gradient update still materialized a complete[vocabulary, hidden_size]matrix before adding each chunk's contribution to the persistent gradient. Direct accumulation removes that intermediate without changing the API, chunking policy, loss calculation, or returned gradient dtype.The existing mixed-precision path for FP16/BF16 operands with an FP32 destination is preserved. Unsupported devices and dtype combinations continue to use the existing fallback.
Fixes #1323 .
Details
The previous same-dtype update used:
This creates a separate
[V, H]matrix-multiplication result. FP16 and BF16 then create an additional FP32 conversion of that result. AtV=32000andH=4096, those intermediates account for 750 MiB in FP16/BF16 and 500 MiB in FP32, independently of the token chunk size.This PR introduces a shared accumulation helper and selects direct accumulation when all three operands use the same supported dtype:
Dispatch behavior
grad_weightgrad_weightgrad_weightout_dtype=torch.float32pathThe BF16 compute-capability check remains BF16-specific. FP16 and FP32 use the same CUDA operand types as the previously supported matrix-multiplication fallback and do not inherit the BF16 hardware restriction.
The new regression test parametrizes FP16, BF16, and FP32 and deliberately fails if a supported same-dtype case reaches the allocating
torch.mmfallback.Benchmark results
Methodology
N=16384,H=4096,V=32000.2.13.0+cu130; Liger candidate applied to baselineed08f6e.torch-lce-autois PyTorch 2.13 native LCE with automatic chunking.torch-lce-512uses the same native implementation with a fixed 512-token chunk.Full all-dtype comparison
Comparison with PyTorch LCE auto
These results do not treat one GPU's capacity as the motivation for the change. The optimization removes an allocation proportional to
V * H; the benchmark hardware is reported only so that the measurements can be reproduced and compared fairly.Focused accumulation result
At
V=32000,H=4096, and a 512-token chunk, extending direct accumulation beyond the BF16-only branch produced:BF16 remains within measurement noise, while FP16 and FP32 remove the full-size temporary and reduce accumulation latency.
Correctness
The standalone gate compared ordinary PyTorch, PyTorch LCE auto, PyTorch LCE with 512-token chunks, and Liger. All loss, input-gradient, and weight-gradient comparisons passed in BF16, FP16, and FP32.
The BF16 loss comparison passes through the relative-tolerance term; its gradient errors remain below
4e-4.Testing Done
make testto ensure correctnessmake checkstyleto ensure code stylemake test-convergenceto ensure convergenceAdditional validation completed:
python -m pytest test/transformers/test_fused_linear_cross_entropy.py -x -q(140 passed)3 passed)ruff check .ruff format --check .