feat(sft):Add optional fused linear ce for qwen2/qwen3 on npu - #9784
Open
yangguang-zhang wants to merge 6 commits into
Open
feat(sft):Add optional fused linear ce for qwen2/qwen3 on npu#9784yangguang-zhang wants to merge 6 commits into
yangguang-zhang wants to merge 6 commits into
Conversation
Added support for NPU fused linear CE in the tuner.
Added a safeguard for accuracy computation during Fused Linear Cross-Entropy training to handle empty logits tensors gracefully. Updated the SwiftMixin class to prevent crashes when encountering a dummy tensor.
Feat npu fused ce
yangguang-zhang
requested a deployment
to
qoder-review
July 22, 2026 07:25 — with
GitHub Actions
Waiting
Contributor
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
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.
PR type
PR information
Background
Training Large Language Models with massive vocabularies (e.g., Qwen2 with a 152K vocab size) on long-context tasks encounters a severe "Memory Wall" at the final layer. In the standard HuggingFace implementation, the LM-Head and CrossEntropyLoss are computed sequentially. This requires materializing a massive
Logitstensor of shape[Batch * SeqLen, VocabSize]in HBM. For instance, withB=1, Seq=8192, this single tensor and its gradients can easily consume >4.5 GB of VRAM, often leading to Out-Of-Memory (OOM) errors on Ascend NPUs and severely limiting the maximum sequence length or batch size.What this PR does
This PR introduces an optional Memory-Efficient Fused LM-Head & CrossEntropy path for Qwen series training on NPU.
When enabled, it patches the
Qwen2ForCausalLM.forward(and its variants) to intercept thehidden_statesbefore they enter thelm_head. It uses a Chunked Autograd strategy in the time dimension:CHUNK_SIZE = 2048).F.linear) and local cross-entropy loss.torch.autograd.grad) and accumulates them.This ensures the full
[Batch * SeqLen, VocabSize]Logits matrix is never materialized in memory.This work is deeply inspired by Liger-Kernel and Unsloth, but is strictly implemented using PyTorch's native APIs (
F.linearandF.cross_entropy) to ensure 100% compatibility with the Ascend NPU's Graph Engine (GE) and PTA dispatcher, completely avoiding compiler issues intriton-ascend.Mathematical Equivalence
The chunking mechanism maintains strict mathematical equivalence to the standard global computation.$Z = X \cdot W^T$ and $L = \text{CE}(Z, Y)$ , the gradients are $\nabla X = \nabla Z \cdot W$ and $\nabla W = (\nabla Z)^T \cdot X$ .$X$ into $[X_1, X_2, ... X_C]$ along the sequence dimension:
Given
By chunking
This summation is implemented via
grad_weight += torch.matmul(grad_logits.t(), x_chunk), guaranteeing exact mathematical fidelity (Gradient Cosine Similarity = 1.000000).Scope
This PR is intentionally scoped to the following cases:
labelsare provided).Safety & Compatibility
To avoid changing the default training behavior, this feature is strictly disabled by default.
FUSED_LINEAR_CE=1to enable it.labels=None), it automatically falls back to the originalself.lm_head(hidden_states).Limitations
The current implementation does not cover the following cases yet:
Experimental Results