Repository navigation
[Fix] GLM-5.3-Flash F2.1 vision training and parallel gradients - #2157
Conversation
…x shape (cherry picked from commit caac8ac)
Base this fix on the F2 vision-tower branch so the later text/compose layer can inherit the shared training corrections. Expand FP32 parameters replicated on an EP/TP submesh to the full world mesh before excluding them from FSDP. Keep full-world replicas and sharded DTensors unchanged. Use an autograd-aware gather for SequenceContext.raw_inputs_embeds so future-token inputs retain gradients across SP shard boundaries. Keep the existing real CPU vision RoPE initialization and make its FP32 dtype and non-persistent-buffer rationale explicit. (cherry picked from commit b715eb9)
Calculate ratios from original global parameter shapes before communication. Discard legacy checkpoint ratios while preserving momentum, steps, and the current clipping policy. Remove the ratio cache and post-load refresh hook. Cover configuration changes, legacy and DCP checkpoint restoration, and 3D/4D/5D convolution update equivalence.
Separate the existing DTensor guard into world-mesh and non-replicated-layout cases. Document plain parameters and fully replicated submesh parameters, including expansion across FSDP rows and normalization when the source mesh already covers all ranks.
| # MTP rolls these embeddings to construct its future-token input. Unlike | ||
| # integer input_ids, this gather must reduce-scatter gradients back to | ||
| # their owners, including gradients crossing an SP shard boundary. | ||
| gathered = all_gather_tensor_autograd(self.inputs_embeds, gather_dim=1, group=self.sequence_parallel_mesh) |
There was a problem hiding this comment.
SP gather 缺少 .contiguous(),非连续 embedding 会报错,原代码中 gather_for_sequence_parallel() 会先执行 input = input.contiguous()
建议改为:
gathered = all_gather_tensor_autograd(
self.inputs_embeds.contiguous(),
gather_dim=1,
group=self.sequence_parallel_mesh,
)|
|
||
| @staticmethod | ||
| def _restore_clip_grad_policy(optimizer: Optimizer, state_dict: dict[str, Any]) -> dict[str, Any]: | ||
| def _prepare_state_dict_for_load(optimizer: Optimizer, state_dict: dict[str, Any]) -> dict[str, Any]: |
There was a problem hiding this comment.
建议不要修改原有的 _restore_clip_grad_policy hook,也不需要在加载时额外清理 lr_ratio。每次更新都会重新计算比例,不读取 checkpoint 中保存的旧值,因此旧值不会影响更新;clip hook 继续只负责恢复 clipping 策略即可。
为了保证后续保存的 state_dict 中,lr_ratio 与更新采用的值一致,建议在 _build_muon_task() 中,根据原始参数的全局 shape 和当前参数组配置重新计算,并将同一个值写回 state、传给更新任务:
lr_ratios = [self._param_lr_ratio(p, group) for p in params]
assert len(set(lr_ratios)) == 1, (
f"Found different lr_ratios: {set(lr_ratios)}"
)
for state, lr_ratio in zip(states, lr_ratios):
# Keep the saved ratio aligned with the value used for this update.
state["lr_ratio"] = lr_ratio后续 muon_update_batch_async() 继续传入 lr_ratio=lr_ratios[0]。这样更新使用重新计算的正确比例,保存 checkpoint 时也自然保存同一个值,无需额外的加载清理或保存时重算逻辑。
Make autograd SP gather inputs contiguous while preserving gradients to the original embedding views. Restore the clipping-only load hook. Compute Muon ratios from global parameter shapes and current groups for every update, write the same ratios back to state, and verify legacy checkpoints, configuration changes, and DCP restoration.
4fc4f66
into
InternLM:feat/glm53flash-f2-vision-tower
| # for Partial, it returns a value pending reduction. | ||
| # Neither can be replicated as the full parameter. | ||
| # Preserve these layouts; converting them is outside this fix. | ||
| if any(not placement.is_replicate() for placement in param.placements): |
There was a problem hiding this comment.
Follow-up on the FP32 ignored-param mesh fix: #2162.
#2157 correctly identified that EP-only FP32 replicas desync FSDP-rank grads for norms/clipping, but the four-way case split in base.py is heavier
than needed.
The invariant is simpler: every FP32 FSDP-ignored parameter should end up as a full-world replica — DTensor(world_mesh, [Replicate()] * ndim).
#2162 always rematerializes that way via full_tensor() + distribute_tensor, instead of preserving alternate meshes/placements. Suggest reviewing
#2162 as a cleaner follow-up to this part of #2157.
|
Follow-up to the Muon conv lr_ratio fix here: #2161 refactors matrix layout so Newton-Schulz and lr_ratio share one _muon_matrix_shape contract (2D/3D), instead of inferring shapes separately. |
This F2.1 follow-up corrects Muon scaling for vision convolution parameters, synchronizes FSDP-ignored FP32 replicas across the complete model mesh, and preserves embedding-input gradients under sequence parallelism.
Target:
feat/glm53flash-f2-vision-tower. Related: #2110.Changes and impact
[out_channels, product(input_dimensions)]used for orthogonalization. Derive the Muon learning-rate ratio from each original global parameter shape and the current parameter-group configuration in_build_muon_task, before communication orto_local(). Pass that fresh ratio to the update and write the same value back to optimizer state, so checkpoints record the ratio computed for the latest update task. Saved checkpoint ratios do not influence updates. Preserve momentum/steps and the original clipping-policy load hook, without ratio-specific load/save hooks. Cover 3D/4D/5D convolution/matrix update equivalence, configuration changes, and legacy/DCP checkpoint restoration. The original convolution fix was cherry-picked from JT-Ushio/xtuner-muonsplit-verify, caac8ac8; the ratio-state handling follows the review suggestion.SequenceContext.raw_inputs_embedswithall_gather_tensor_autograd, makinginputs_embedscontiguous before the collective to support transposed and strided embedding views. The contiguous copy preserves autograd; backward uses reduce-scatter SUM to return contributions to their owning ranks, including MTP future-token dependencies crossing SP shard boundaries. Keep the cached gathered tensor attached to its graph.torch.float32and document why the non-persistent buffer must remain real during meta construction.Validation
Current head
a0c799ba: review follow-up (October 12):SequenceContextproperty and MTP packed-roll code matched the full-sequence forward and backward references exactly, including gradients to the original leaf tensor across an SP boundary. Cache, no-grad, non-SP and None checks also passed. The standalone SP validation code remains outside the commit.git diff --checkpassed for all three files changed in this follow-up. Full pre-commit was unavailable in the runtime. No new collectives were added; contiguous inputs retain the existing storage, while non-contiguous inputs require a copy. No throughput benchmark was run.Earlier F2.1 validation at
06298610, compared with F299266d89(October 12):[1, 2, 3, 4]to1.5/3.5; F2.1 reduced them to2.5on every rank. With nonuniform gradient components, the replica parameter difference after two clipped updates fell from 0.0622052 to 0, matching the global-gradient reference. Native FSDP wrapping was stubbed for this CPU test.rtol=1e-5, atol=1e-5. Twenty raw patches were padded to 24, processed through Ulysses and the local projector, then trimmed to five merged tokens. The maximum difference versus non-SP was 0.torch.cpu.reset_peak_memory_stats. In a separate CPU-adapted check, disabling only GPU memory profiling and accelerator synchronization allowed all 347 vision/projector parameters to load with 0 missing/unloaded keys and correct analytical FP32 RoPE frequencies. This adapted pass does not erase the original CPU compatibility failure.git diff --checkpassed. Full pre-commit was not run.The earlier
06298610results above used CPU/Gloo. The current review follow-up adds the CUDA/NCCL Muon and embedding-gather checks listed first; full 25B training, full Trainer/FSDP resume, compile, and throughput were not rerun. The current F2 baseline already has real CPU RoPE initialization; this PR's RoPE change explicitly names the FP32 dtype and updates its comments.Earlier GPU evidence for the FP32/SP fixes (September 29–30):
The earlier GPU runs used an older GLM53 snapshot and AdamW; they provide evidence for the FP32/SP fixes, rather than full-model training validation of the current combined head. Current Muon CUDA/NCCL checks are listed separately above. Strict full-model numerical equivalence across SP sizes remains unresolved. No before/after throughput benchmark was run.