train: real batched step (drop loop+SUM)
Feed a real batch of B sequences as ONE batched forward/backward, replacing the "loop B times + let the tape SUM grads + clip ×1/B" hack. CE mean over B*S rows is already the batch-mean loss, so backward yields the batch-mean gradient directly → clip pre-scale = 1.0. DDP stays equivalent: each rank runs one batched forward over its b_local = B_global/world sequences (local-mean grad Σ_local/b_local); all_reduce_average (sum across ranks /world) = Σ_global/B_global = global batch-mean → clip pre-scale 1.0. The ddp_correctness single-GPU baseline batches the same way. DDP loss matches single-GPU 5.7e-7, cross-rank params bit-identical (0.0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ use std::time::Instant;
|
||||
|
||||
use xtrain_cuda::device;
|
||||
use xtrain_distributed::{DdpConfig, DdpContext, build_model, get_unique_id, launch, train_rank};
|
||||
use xtrain_model::{Config, ids_tensor};
|
||||
use xtrain_model::{Config, batched_ids_tensor};
|
||||
use xtrain_optim::GpuAdamW;
|
||||
use xtrain_tensor::Device;
|
||||
use xtrain_train::clip::clip_grad_norm_gpu;
|
||||
@@ -47,22 +47,25 @@ fn run_single_gpu(cfg: Config, corpus: &Corpus, dcfg: &DdpConfig) -> (Vec<f32>,
|
||||
let params = model.params();
|
||||
let mut opt = GpuAdamW::new(dcfg.weight_decay);
|
||||
let mut rng = dcfg.seed;
|
||||
let inv_batch = 1.0 / dcfg.batch_size as f32;
|
||||
let mut losses = Vec::new();
|
||||
|
||||
for step in 0..dcfg.steps {
|
||||
let lr = dcfg.schedule.lr(step);
|
||||
let mut loss_sum = 0.0f32;
|
||||
// Sample the whole global batch and run it as ONE batched forward/backward
|
||||
// (matches the T10 DDP path: backward yields the global-batch mean grad).
|
||||
let mut inputs = Vec::with_capacity(dcfg.batch_size);
|
||||
let mut targets_v = Vec::with_capacity(dcfg.batch_size);
|
||||
for _ in 0..dcfg.batch_size {
|
||||
let (input, target) = corpus.sample(dcfg.seq_len, &mut rng);
|
||||
let ids = ids_tensor(&input, device);
|
||||
let targets = ids_tensor(&target, device);
|
||||
let loss = model.loss(&ids, &targets);
|
||||
loss_sum += loss.value().to_device(Device::Cpu).as_slice::<f32>()[0];
|
||||
loss.backward();
|
||||
inputs.push(input);
|
||||
targets_v.push(target);
|
||||
}
|
||||
losses.push(loss_sum * inv_batch);
|
||||
clip_grad_norm_gpu(¶ms, dcfg.max_grad_norm, inv_batch);
|
||||
let ids = batched_ids_tensor(&inputs, device);
|
||||
let targets = batched_ids_tensor(&targets_v, device);
|
||||
let loss = model.loss_batched(&ids, &targets, dcfg.batch_size);
|
||||
losses.push(loss.value().to_device(Device::Cpu).as_slice::<f32>()[0]);
|
||||
loss.backward();
|
||||
clip_grad_norm_gpu(¶ms, dcfg.max_grad_norm, 1.0);
|
||||
opt.step(lr, ¶ms);
|
||||
for p in ¶ms {
|
||||
p.zero_grad();
|
||||
|
||||
Reference in New Issue
Block a user