train_grpo.py, train_ppo.py and train_agent.py wrap the policy in DistributedDataParallel but run the loss-bearing forward through .module, bypassing the wrapper. DDP arms its gradient all-reduce hooks inside DistributedDataParallel.forward(), so calling .module directly means backward() performs no all-reduce: every rank steps on purely local gradients and the replicas silently diverge. Only rank 0 is saved, so multi-GPU RL training quietly degrades to single-GPU training on 1/N of the data with no error. The supervised trainers are unaffected; they already call the wrapped module. no_grad uses of .module (rollout generation, checkpoint saving) are left untouched, where unwrapping is correct. Single-GPU behaviour is unchanged: with no process group, model is the bare module and these calls are identical to before. |
||
|---|---|---|
| .. | ||
| rollout_engine.py | ||
| train_agent.py | ||
| train_distillation.py | ||
| train_dpo.py | ||
| train_full_sft.py | ||
| train_grpo.py | ||
| train_lora.py | ||
| train_ppo.py | ||
| train_pretrain.py | ||
| train_tokenizer.py | ||
| trainer_utils.py | ||