fix: correct LoRA initialization and forward pass under tensor parallelism#150
Open
chen2021673 wants to merge 7 commits into
Open
fix: correct LoRA initialization and forward pass under tensor parallelism#150chen2021673 wants to merge 7 commits into
chen2021673 wants to merge 7 commits into
Conversation
chen2021673
force-pushed
the
lora_ddp_loss
branch
from
May 14, 2026 09:08
8459156 to
f918ae3
Compare
chen2021673
force-pushed
the
lora_ddp_loss
branch
2 times, most recently
from
June 5, 2026 05:22
d2c8f7a to
f4f2220
Compare
Chamberlain0w0
requested changes
Jun 11, 2026
| int64_t shard_size = dims[shard_dim] / tp_size; | ||
| int64_t start = parallel::tp_rank * shard_size; | ||
| auto sliced = cpu_tensor->Slice(shard_dim, start, start + shard_size); | ||
| dst->CopyFrom(sliced); |
Contributor
There was a problem hiding this comment.
现在模型实现中,Attention 里面第一个 Linear 把 QKV 合并了(实际排列上是 [Q | K | V]),LoadFromLLMC 里面有对应的处理(如 TP=4,则切成 [Q0 Q1 Q2 Q3 | K0 K1 K2 K3 | V0 V1 V2 V3],然后依次拼接 [Qi | Ki | Vi] load 到每个 tp rank 上)。所以这块的切分逻辑对于这种情况没法适用,得想想看怎么能特别处理一下
Contributor
Author
There was a problem hiding this comment.
加一个特判,在 LoadLoRAWeights 里识别 attn.c_attn 这种输出维分片参数,把 full [Q|K|V] 切成 local [Qi|Ki|Vi]。
Contributor
Author
There was a problem hiding this comment.
checkpoint 没单独处理这个类型,load 的时候必须对得上 TP 的配置。但这里因为要和单机对齐初始化参数,有这个功能需求。
chen2021673
force-pushed
the
lora_ddp_loss
branch
2 times, most recently
from
June 16, 2026 09:00
50ff3b8 to
2d55720
Compare
chen2021673
force-pushed
the
lora_ddp_loss
branch
from
June 23, 2026 08:21
2d55720 to
f408788
Compare
Chamberlain0w0
approved these changes
Jun 24, 2026
kilinchange
requested changes
Jun 30, 2026
…ence Inline base and LoRA matmuls, add locally, then issue a single AllGather/AllReduce instead of two separate collective ops. The prior two-collective approach caused floating-point divergence in DDP loss. Also fix LoadLoRAWeights to slice sharded tensors by tp_rank when the checkpoint shape differs from the partitioned model shape.
Introduce new multi-stream Broadcast and Scatter APIs that take a root_rank_in_group argument, and rename the legacy single-stream variants to BroadCast_/Scatter_ to disambiguate.
chen2021673
force-pushed
the
lora_ddp_loss
branch
2 times, most recently
from
July 22, 2026 07:09
0232eac to
02cb5ed
Compare
kilinchange
approved these changes
Jul 22, 2026
Collaborator
|
麻烦修改一下 3b6088e 这个 commit 的 message,然后再跑一遍全量测试吧。 |
Chamberlain0w0
approved these changes
Jul 22, 2026
chen2021673
force-pushed
the
lora_ddp_loss
branch
from
July 22, 2026 07:27
02cb5ed to
4587641
Compare
SaveLoRAWeights now gathers TP-sharded LoRA tensors into full/unsharded tensors before writing, so adapter files are portable across TP sizes. Only TP rank 0 in the primary DP/PP group writes the file. LoadLoRAWeights slices full tensors back to the current rank's local shard. Attention c_attn.lora_B uses the packed QKV [Q | K | V] layout: it is restored from per-rank [Qi | Ki | Vi] shards on save and re-split per rank on load, matching how base QKV checkpoints are handled. Add detail:: helpers SlicePackedQKVRowsForTensorParallel and RestorePackedQKVRowsFromTensorParallel with unit tests covering GPT-style and GQA-style QKV layouts.
Expose the wrapped module from DDP and save LoRA adapters from the inner model, matching PyTorch's model.module.state_dict() pattern. Also consume a legacy leading module. prefix when loading LoRA adapter state dicts, add test coverage.
- move TP shard gathering into parallel utils - reuse it in TP autograd and LoRA checkpoint paths - document pending DDP and checkpoint integration work - simplify LoRA tests with Tensor::To
Contributor
Author
已修改。 |
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.
Summary
Fix LoRA loss divergence under tensor/data parallel training by making LoRA tensor-parallel initialization deterministic and aligning the forward collective order between base linear and LoRA linear paths.
This PR changes TP LoRA parallel linear modules to compute the base shard and LoRA shard locally first, add them before communication, and then run a single TP collective on the combined output. It also adds rank-aware
Broadcast/ScatterProcessGroup APIs and updates LoRA weight loading to support loading full saved LoRA tensors into TP-sharded model parameters.It also adds rank-aware
Broadcast/ScatterProcessGroup APIs, updates LoRA adapter save/load to use portable full tensors under TP, handles packed QKV LoRA tensors, and keeps adapter IO compatible with DDP-wrapped models.Motivation
In tensor-parallel LoRA training, the base linear output and the LoRA update together form one logical linear output. Previously, the base path and LoRA path could run separate TP collectives and add their outputs afterward:
This changes the floating-point communication/reduction order compared with computing the logical local contribution first:
The separate-collective path can introduce numerical divergence across TP/DDP configurations.
Replicated or sharded LoRA parameters need rank-consistent initialization so every TP rank starts from the same logical LoRA weights.
Key Changes
LoRA parallel linear forward
Update
LoRAColumnParallelLinearto:base_shard + scaled_lora_shardbefore TP gather;gather_output_is enabled.Update
LoRARowParallelLinearto:base_shard + scaled_lora_shardbefore TP reduce/reduce-scatter;RowParallelLinearbehavior.This makes the LoRA path follow the same logical communication boundary as the base parallel linear layer and avoids running separate collectives for base and LoRA outputs.
Deterministic TP LoRA initialization
lora_Aconsistent across TP ranks.lora_Afrom TP rank 0 and distribute the correct local shards to each TP rank.ProcessGroup communication APIs
Add rank-aware communication APIs:
ProcessGroup::Broadcast(tensors, root_rank_in_group, async_op)ProcessGroup::Scatter(output_tensors, input_tensors, root_rank_in_group, async_op)Rename the old APIs to
BroadCast_/Scatter_to avoid semantic ambiguity.Update existing autograd communication wrappers to call the legacy renamed APIs where appropriate.
LoRA weight save/load
Extend
LoadLoRAWeightsto support loading full saved LoRA weights into TP-sharded model parameters.When a destination parameter is TP-sharded, slice the loaded full tensor according to the current
tp_rankbefore copying it into the local parameter.Update
SaveLoRAWeightsto export portable full LoRA weights under TP:dp == 0 && tp == 0 && pp == 0writes the weight file.Packed QKV LoRA tensor handling
c_attn.lora_Bspecially when it uses the packed QKV layout[Q | K | V].[Qi | Ki | Vi]shards.[Qi | Ki | Vi]shards for the current TP rank.DDP adapter state dict compatibility
DistributedDataParalleland save LoRA adapters from the inner model.model.module.state_dict()behavior for DDP-wrapped models.module.prefix when loading LoRA adapter state dicts.module.prefix compatibility.Test
The loss values in the LoRA tests fluctuate slightly, which is expected because the tests now use saved fixed initialization values.
The performance variance is concentrated in the
lora/bfloat16/distopttests and is treated as normal fluctuation.