Repository navigation
Conversation
Qwen3.5's linear-attention layers (linear_attn and input_layernorm) are replicated on every tensor-parallel rank rather than sharded, but nothing synchronizes their gradients across TP. Each rank computes the same full gradient mathematically, yet nondeterministic kernels make the replicas drift apart a little more every step, so TP ranks end up training slightly different weights and a checkpoint keeps only one of them. Mark these parameters with average_gradients_across_tp_domain so Megatron's finalize_model_grads all-reduces their gradients across the TP group.
|
Additional evidence, still on a slime 0.3.0-based build (P6 B200, 10 steps each). This change on four Qwen3.5 layouts. The flag is set in
Numerics, 35B-A3B. Same seed and data: two runs with this change (F1, F2) and one without it (U).
Without the change, 1656 of 2400 replicated rank-params differ across TP by step 10. With it, none do. Step time is unchanged (72.4 / 71.9 s vs 71.9 s). CI. The only failing check, Ready for review whenever someone has time. |
Summary
In the Qwen3.5 spec,
slime_plugins/models/qwen3_5.pyadds the linear-attention layers (linear_attn=Qwen3_5GatedDeltaNet, plusinput_layernorm) as aHuggingfaceAttention. These parameters are replicated on every tensor-parallel rank, not sharded, but nothing synchronizes their gradients across TP.hf_attention.pygathers the sequence-parallel input before these modules, so in exact arithmetic every TP rank computes the same full gradient. In practice the kernels are not bitwise deterministic across ranks. The replicas drift apart a little more every step, so TP ranks end up training slightly different weights, and a distributed checkpoint keeps only one of the copies.This PR marks these parameters with
average_gradients_across_tp_domain = True. Megatron'sfinalize_model_grads(_allreduce_non_tensor_model_parallel_grads) then averages their gradients across the TP group, so the replicas stay identical. With TP=1 it is a no-op: that path returns early when the TP group size is 1.Evidence
A/B on Qwen3.5-9B SFT, 2 nodes × 8 B200, TP=2 / PP=2, 30 training steps, same data and seed. The only difference is the gradient flag. A test-only probe compared each replicated parameter across the 2 TP ranks after every step (all-reduce MAX − MIN):
We first saw this in a strict save/restore check that compares per-rank tensor fingerprints (Qwen3.5-35B, TP2). At save time, the source TP ranks already held different values for these replicated weights. The checkpoint stores a single copy, so the restored TP1 no longer matched the source TP1. In a 122B A/B, the extra all-reduce cost +0.24% step time.
These runs used a slime 0.3.0-based build. On
main, theAttentionclass touched here differs only by a newnameargument, and the sequence-parallel gather/scatter inhf_attention.pyis the same. I haven't rerun the A/B onmain.Notes
qwen3_next.pybuilds its linear attention the same way and may need the same change. I haven't measured it, so it's not included here.