train.py85 linesGitHub: train.py1import math2import numpy as np3import config4from data import load_corpus, encode_corpus, split_ids, make_windows, iterate_batches5from checkpoint import save_checkpoint6from generate import generate7from ops import cross_entropy_forward, perplexity8from optim import Adam, clip_grad_norm, lr_schedule9from tokenizer import build_tokenizer10from transformer import ModelConfig, init_params, forward, loss_and_grads1112def batch_loss_and_grads(params, xb, yb, cfg: ModelConfig):13 B = len(xb)14 grads = {k: np.zeros_like(v) for k, v in params.items()}15 total_loss = 0.01617 for x, y in zip(xb, yb):18 loss, g = loss_and_grads(params, x, y, cfg)19 total_loss += loss / B2021 for k in grads:22 grads[k] += g[k] / B2324 return total_loss, grads2526def validation_loss(params, cfg, inputs, targets):27 losses = []2829 for x, y in zip(inputs.to_numpy(), targets.to_numpy()):30 logits, _ = forward(params, x, cfg)31 loss, _ = cross_entropy_forward(logits, y)32 losses.append(loss)3334 return float(np.mean(losses))3536def main(prefix="checkpoints/model"):37 rng = np.random.default_rng(config.seed)3839 # 1. text -> ids -> train/val windows (split BEFORE windowing)40 text = load_corpus(config.corpus_path, config.corpus_column, config.max_rows)41 tok = build_tokenizer(text, config.num_merges)42 ids = encode_corpus(text, tok)43 train_ids, val_ids = split_ids(ids, config.val_fraction)44 tr_x, tr_y = make_windows(train_ids, config.seq_len, config.stride)45 va_x, va_y = make_windows(val_ids, config.seq_len, config.stride)4647 # 2. model + optimiser48 cfg = ModelConfig(tok.vocab_size, config.context_len, config.emb_dim,49 config.num_heads, config.ff_dim, config.num_layers)50 params = init_params(cfg, rng)51 opt = Adam(params, config.beta1, config.beta2, config.adam_eps, config.weight_decay)52 print(f"V={cfg.vocab_size} ln V={math.log(cfg.vocab_size):.3f}")5354 steps_per_epoch = math.ceil(len(tr_x) / config.batch_size)55 total_steps = config.epochs * steps_per_epoch5657 # 3. the loop: gradient -> clip -> learning rate -> Adam58 step = 059 for epoch in range(config.epochs):60 for xb, yb in iterate_batches(tr_x, tr_y, config.batch_size, rng):61 loss, grads = batch_loss_and_grads(params, xb, yb, cfg)62 norm = clip_grad_norm(grads, config.grad_clip)63 step += 164 lr = lr_schedule(step, config.warmup_steps, total_steps,65 config.lr_max, config.lr_min)66 opt.step(params, grads, lr)67 if step == 1 or step % 50 == 0:68 print(f"step {step:5d} loss {loss:.3f} |g| {norm:.2f} lr {lr:.5f}")6970 v = validation_loss(params, cfg, va_x, va_y)71 print(f"epoch {epoch + 1}: val loss {v:.3f} ppl {perplexity(v):.1f}")72 seed_ids = [int(i) for i in va_x.iloc[0][:3]]73 out = generate(params, cfg, seed_ids, 30, config.seq_len,74 config.temperature, config.top_k, config.top_p, rng)75 print(" sample:", repr(tok.decode(out)))7677 # 4. keep the trained model so talk.py can load it later78 save_checkpoint(prefix, params, cfg, tok)79 print(f"saved checkpoint to {prefix}.*")8081 return params, cfg, tok828384if __name__ == "__main__":85 main()