fix(post_train): Fix Tunix SFT signatures, Qwix LoRA mesh sharding, and scale Qwen/LLaMA parallelism - #4866
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for gradient accumulation and conditional optimizer updates in the SFT trainer, and updates LoRA initialization to dynamically compute dummy input shapes based on the mesh topology. A critical issue was identified in the gradient accumulation logic: checking the truthiness of grad_accumulator.grads can evaluate to False on the first step if it is empty or uninitialized, which would permanently bypass gradient accumulation. It is recommended to simplify this check to only verify the presence of the add method.
| if ( | ||
| grad_accumulator is not None | ||
| and hasattr(grad_accumulator, "add") | ||
| and hasattr(grad_accumulator, "grads") | ||
| and bool(getattr(grad_accumulator, "grads", None)) | ||
| ): |
There was a problem hiding this comment.
Checking bool(getattr(grad_accumulator, "grads", None)) can cause gradient accumulation to be completely bypassed. If grad_accumulator.grads is initialized to None or is empty on the first step, this condition evaluates to False. As a result, the code will fall back to the else block, directly updating the optimizer and never calling grad_accumulator.add(grads). This means gradient accumulation will be permanently disabled. To fix this, simplify the condition to only check if grad_accumulator is not None and has the add method.
if grad_accumulator is not None and hasattr(grad_accumulator, "add"):
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
5731a07 to
36c76c5
Compare
3f7eaf9 to
ceb170a
Compare
…emma4 per-expert scaling, and scale Qwen/LLaMA parallelism - Standardize Tunix PeftTrainer is_update_step train_step signature and micro-batch accumulation - Resolve Qwix LoRA IndivisibleError by computing product of data-parallel axes during tracing - Fix Gemma4 MoE forward pass by restoring per_expert_scale scaling for non-fused calls - Fix Qwen MoE 3D expert kernel transposition in QWEN_MAXTEXT_TO_HF_PARAM_HOOK_FN - Configure Qwen3-30B logit checker with dtype=float32 and per_device_batch_size=1 - Enable remat_policy=full for LLaMA 3.1 70B post-training workflows - Scale Qwen3-30B post-training mesh to 32 cores (v5p-32)
ceb170a to
2aebc78
Compare
Description
Motivation & Background
This PR addresses multiple blocking regressions across post-training workflows (Tunix SFT, Qwix LoRA fine-tuning, and RL rollouts), MoE checkpoint conversions, and hardware scalability in MaxText. These issues caused persistent failures on Cloud Composer TPU end-to-end testing pipelines.
Detailed Changes
1. Gemma 4 MoE
per_expert_scaleForward Pass FixRoutedMoELegacyscaledwo_kernelduring non-fused forward passes (wo_kernel * per_expert_scale). During the Flax NNX migration,wowas converted tolinears.DenseGeneral, andper_expert_scalemultiplication was accidentally omitted for non-fused/training calls inRoutedMoE.src/maxtext/layers/moe.py, restoredper_expert_scalemultiplication ontop_k_weightsinsideRoutedMoE.gate()for selected top-k experts whenfuse_expert_scalesis false.2. Tunix
is_update_stepSignature Alignment inMaxTextPeftTrainerPeftTrainer.train()passes(model, optimizer, grad_accumulator)as partial arguments and invokestrain_step(inputs, is_update_step=...).MaxTextPeftTrainer.create_train_step_fn()had an outdated signature(model, optimizer, inputs, grad_accumulator=None), causingTypeError: train_step() got an unexpected keyword argument 'is_update_step'across all Tunix SFT runs (gemma3-4b.sft,gpt-oss-20b.sft,llama3_1_70b.sft).(model, optimizer, grad_accumulator, inputs, is_update_step=True, **kwargs).is_update_step=True), accumulating gradients across micro-batches otherwise.3. Qwix LoRA Sharding
IndivisibleErroron Multi-Device FSDP Mesheslora_utils.apply_lora_to_modelcreated dummy tracing inputs usingdp_size = mesh.shape['data'](defaulting to 1 whendata=1). On partitioned multi-device meshes (e.g.v5p-128withfsdp=64), JAX threwIndivisibleErrorbecause batch dimension 1 was not divisible by the partition factor (64).dp_sizecalculation to compute the product of all data-parallel mesh axes:dp_size = mesh.shape.get('data', 1) * mesh.shape.get('fsdp', 1) * mesh.shape.get('fsdp_transpose', 1) * mesh.shape.get('expert', 1)seq_lento compute the product of sequence-parallel axes (tensor_sequence,context).4. MoE Checkpoint Conversion & Qwen3 Hardware Scalability
reshape_expert_kernelinparam_mapping.pyto preserve expert axis 0 (transpose(0, 2, 1)) for 3D MoE expert weights, separating 2D gate/router hooks from 3D expert hooks.v5p-32): Scaled Qwen3-30B SFT and RL test scripts from 128 cores (v5p-32/ 16 devices) withTP=4, FSDP=2, EP=2(test_qwen3_sft.sh,test_qwen3_rl.sh), reducing resource footprint by 75%.dtype=float32andper_device_batch_size=1totest_qwen3_to_mt.shforward-pass logit checker with--max_kl_div=0.05.5. Memory Protection & Model Stability
remat_policy=fullacross SFT and RL test scripts to prevent Out-Of-Memory (OOM) failures on 70B parameter footprints.ici_fsdp_parallelism=64fromtest_gpt_oss.shto allow dynamic auto-sharding onv5p-8, and set rolloutTP=1for single-host execution.torchvisioninstall totest_qwen3_multimodal_sft.shfor multimodal image processing.Tests
tests/post_training/unit/train_sft_test.py,tests/post_training/unit/lora_utils_test.py).codespell,pylint,pyink, andyamllintall pass with 0 errors.Checklist
gemini-reviewlabel.