Andrej Karpathy commited on
Commit
2c062aa
·
1 Parent(s): f41dd3c

nit: don't mutate args, create new var for total_batch_size

Browse files
Files changed (1) hide show
  1. scripts/base_train.py +18 -16
scripts/base_train.py CHANGED
@@ -256,13 +256,15 @@ num_scaling_params = get_scaling_params(model)
256
  target_tokens = int(args.target_param_data_ratio * num_scaling_params)
257
 
258
  # Auto-compute optimal batch size based on Power Lines paper (Bopt ∝ D^0.383), ref: https://arxiv.org/abs/2505.13738
259
- if args.total_batch_size == -1:
 
260
  d12_ref = build_model_meta(12) # d12 is where the optimal batch size was measured to be 2**19 tokens
261
  d12_num_scaling_params = get_scaling_params(d12_ref)
262
  D_REF = args.target_param_data_ratio * d12_num_scaling_params
263
  B_REF = 2**19
264
- args.total_batch_size = 2 ** round(math.log2(B_REF * (target_tokens / D_REF) ** 0.383)) # also clamp to power of 2
265
- print0(f"Auto-computed optimal batch size: {args.total_batch_size:,} tokens")
 
266
 
267
  # Calculate number of iterations. Either it is given, or from target flops, or from target data:param ratio (in that order)
268
  assert args.num_iterations > 0 or args.target_param_data_ratio > 0 or args.target_flops > 0
@@ -272,17 +274,17 @@ if args.num_iterations > 0:
272
  print0(f"Using user-provided number of iterations: {num_iterations:,}")
273
  elif args.target_flops > 0:
274
  # Calculate the number of iterations from the target flops (used in scaling laws analysis, e.g. runs/scaling_laws.sh)
275
- num_iterations = round(args.target_flops / (num_flops_per_token * args.total_batch_size))
276
  print0(f"Calculated number of iterations from target FLOPs: {num_iterations:,}")
277
  elif args.target_param_data_ratio > 0:
278
  # Calculate the number of iterations from the target param data ratio (the most common use case)
279
- num_iterations = target_tokens // args.total_batch_size
280
  print0(f"Calculated number of iterations from target data:param ratio: {num_iterations:,}")
281
  else:
282
  raise ValueError("No training horizon specified")
283
- total_tokens = args.total_batch_size * num_iterations
284
  print0(f"Total number of training tokens: {total_tokens:,}")
285
- print0(f"Tokens : Scaling params ratio: {args.total_batch_size * num_iterations / num_scaling_params:.2f}") # Chinchilla is ~20
286
  print0(f"Total training FLOPs estimate: {num_flops_per_token * total_tokens:e}")
287
 
288
  # -----------------------------------------------------------------------------
@@ -290,22 +292,22 @@ print0(f"Total training FLOPs estimate: {num_flops_per_token * total_tokens:e}")
290
  # figure out the needed gradient accumulation to reach the desired total batch size
291
  tokens_per_fwdbwd = args.device_batch_size * args.max_seq_len # tokens per iteration for a single rank
292
  world_tokens_per_fwdbwd = tokens_per_fwdbwd * ddp_world_size # total tokens per iteration for all ranks
293
- assert args.total_batch_size % world_tokens_per_fwdbwd == 0
294
- grad_accum_steps = args.total_batch_size // world_tokens_per_fwdbwd
295
  print0(f"Tokens / micro-batch / rank: {args.device_batch_size} x {args.max_seq_len} = {tokens_per_fwdbwd:,}")
296
  print0(f"Tokens / micro-batch: {world_tokens_per_fwdbwd:,}")
297
- print0(f"Total batch size {args.total_batch_size:,} => gradient accumulation steps: {grad_accum_steps}")
298
 
299
  # Batch size scaling for learning rates (hyperparameters were tuned at reference batch size 2^19)
300
  batch_lr_scale = 1.0
301
  reference_batch_size = 2**19
302
- batch_ratio = args.total_batch_size / reference_batch_size
303
  if batch_ratio != 1.0:
304
  # SGD: linear scaling with batch size is standard (not used in nanochat)
305
  # AdamW: sqrt scaling is standard
306
  # Muon: sqrt scaling is an assumption - not fully studied, but it's a second-order-ish optimizer
307
  batch_lr_scale = batch_ratio ** 0.5
308
- print0(f"Scaling LRs by {batch_lr_scale:.4f} for batch size {args.total_batch_size:,} (reference: {reference_batch_size:,})")
309
 
310
  # Weight decay is tuned at d12 and its scaling seems to be \propto 1/channels^2 (or equivalently, \propto 1/depth^2 due to constant aspect ratio)
311
  weight_decay_scaled = args.weight_decay * (12 / args.depth)**2
@@ -381,7 +383,7 @@ else:
381
  # Training loop
382
  while True:
383
  last_step = step == num_iterations # loop runs num_iterations+1 times so that we can eval/save at the end
384
- flops_so_far = num_flops_per_token * args.total_batch_size * step
385
 
386
  # once in a while: evaluate the val bpb (all ranks participate)
387
  if args.eval_every > 0 and (last_step or step % args.eval_every == 0):
@@ -501,8 +503,8 @@ while True:
501
  smooth_train_loss = ema_beta * smooth_train_loss + (1 - ema_beta) * train_loss_f # EMA the training loss
502
  debiased_smooth_loss = smooth_train_loss / (1 - ema_beta**(step + 1)) # debias the EMA
503
  pct_done = 100 * step / num_iterations
504
- tok_per_sec = int(args.total_batch_size / dt)
505
- flops_per_sec = num_flops_per_token * args.total_batch_size / dt
506
  mfu = 100 * flops_per_sec / (gpu_peak_flops * ddp_world_size)
507
  if step > 10:
508
  total_training_time += dt # only count the time after the first 10 steps
@@ -560,7 +562,7 @@ get_report().log(section="Base model training", data=[
560
  "Number of FLOPs per token": f"{num_flops_per_token:e}",
561
  "Calculated number of iterations": num_iterations,
562
  "Number of training tokens": total_tokens,
563
- "Tokens : Scaling params ratio": args.total_batch_size * num_iterations / num_scaling_params,
564
  "DDP world size": ddp_world_size,
565
  "warmup_ratio": args.warmup_ratio,
566
  "warmdown_ratio": args.warmdown_ratio,
 
256
  target_tokens = int(args.target_param_data_ratio * num_scaling_params)
257
 
258
  # Auto-compute optimal batch size based on Power Lines paper (Bopt ∝ D^0.383), ref: https://arxiv.org/abs/2505.13738
259
+ total_batch_size = args.total_batch_size
260
+ if total_batch_size == -1:
261
  d12_ref = build_model_meta(12) # d12 is where the optimal batch size was measured to be 2**19 tokens
262
  d12_num_scaling_params = get_scaling_params(d12_ref)
263
  D_REF = args.target_param_data_ratio * d12_num_scaling_params
264
  B_REF = 2**19
265
+ batch_size_ratio = target_tokens / D_REF
266
+ total_batch_size = 2 ** round(math.log2(B_REF * batch_size_ratio ** 0.383)) # also clamp to power of 2
267
+ print0(f"Auto-computed optimal batch size: {total_batch_size:,} tokens")
268
 
269
  # Calculate number of iterations. Either it is given, or from target flops, or from target data:param ratio (in that order)
270
  assert args.num_iterations > 0 or args.target_param_data_ratio > 0 or args.target_flops > 0
 
274
  print0(f"Using user-provided number of iterations: {num_iterations:,}")
275
  elif args.target_flops > 0:
276
  # Calculate the number of iterations from the target flops (used in scaling laws analysis, e.g. runs/scaling_laws.sh)
277
+ num_iterations = round(args.target_flops / (num_flops_per_token * total_batch_size))
278
  print0(f"Calculated number of iterations from target FLOPs: {num_iterations:,}")
279
  elif args.target_param_data_ratio > 0:
280
  # Calculate the number of iterations from the target param data ratio (the most common use case)
281
+ num_iterations = target_tokens // total_batch_size
282
  print0(f"Calculated number of iterations from target data:param ratio: {num_iterations:,}")
283
  else:
284
  raise ValueError("No training horizon specified")
285
+ total_tokens = total_batch_size * num_iterations
286
  print0(f"Total number of training tokens: {total_tokens:,}")
287
+ print0(f"Tokens : Scaling params ratio: {total_batch_size * num_iterations / num_scaling_params:.2f}") # Chinchilla is ~20
288
  print0(f"Total training FLOPs estimate: {num_flops_per_token * total_tokens:e}")
289
 
290
  # -----------------------------------------------------------------------------
 
292
  # figure out the needed gradient accumulation to reach the desired total batch size
293
  tokens_per_fwdbwd = args.device_batch_size * args.max_seq_len # tokens per iteration for a single rank
294
  world_tokens_per_fwdbwd = tokens_per_fwdbwd * ddp_world_size # total tokens per iteration for all ranks
295
+ assert total_batch_size % world_tokens_per_fwdbwd == 0
296
+ grad_accum_steps = total_batch_size // world_tokens_per_fwdbwd
297
  print0(f"Tokens / micro-batch / rank: {args.device_batch_size} x {args.max_seq_len} = {tokens_per_fwdbwd:,}")
298
  print0(f"Tokens / micro-batch: {world_tokens_per_fwdbwd:,}")
299
+ print0(f"Total batch size {total_batch_size:,} => gradient accumulation steps: {grad_accum_steps}")
300
 
301
  # Batch size scaling for learning rates (hyperparameters were tuned at reference batch size 2^19)
302
  batch_lr_scale = 1.0
303
  reference_batch_size = 2**19
304
+ batch_ratio = total_batch_size / reference_batch_size
305
  if batch_ratio != 1.0:
306
  # SGD: linear scaling with batch size is standard (not used in nanochat)
307
  # AdamW: sqrt scaling is standard
308
  # Muon: sqrt scaling is an assumption - not fully studied, but it's a second-order-ish optimizer
309
  batch_lr_scale = batch_ratio ** 0.5
310
+ print0(f"Scaling LRs by {batch_lr_scale:.4f} for batch size {total_batch_size:,} (reference: {reference_batch_size:,})")
311
 
312
  # Weight decay is tuned at d12 and its scaling seems to be \propto 1/channels^2 (or equivalently, \propto 1/depth^2 due to constant aspect ratio)
313
  weight_decay_scaled = args.weight_decay * (12 / args.depth)**2
 
383
  # Training loop
384
  while True:
385
  last_step = step == num_iterations # loop runs num_iterations+1 times so that we can eval/save at the end
386
+ flops_so_far = num_flops_per_token * total_batch_size * step
387
 
388
  # once in a while: evaluate the val bpb (all ranks participate)
389
  if args.eval_every > 0 and (last_step or step % args.eval_every == 0):
 
503
  smooth_train_loss = ema_beta * smooth_train_loss + (1 - ema_beta) * train_loss_f # EMA the training loss
504
  debiased_smooth_loss = smooth_train_loss / (1 - ema_beta**(step + 1)) # debias the EMA
505
  pct_done = 100 * step / num_iterations
506
+ tok_per_sec = int(total_batch_size / dt)
507
+ flops_per_sec = num_flops_per_token * total_batch_size / dt
508
  mfu = 100 * flops_per_sec / (gpu_peak_flops * ddp_world_size)
509
  if step > 10:
510
  total_training_time += dt # only count the time after the first 10 steps
 
562
  "Number of FLOPs per token": f"{num_flops_per_token:e}",
563
  "Calculated number of iterations": num_iterations,
564
  "Number of training tokens": total_tokens,
565
+ "Tokens : Scaling params ratio": total_batch_size * num_iterations / num_scaling_params,
566
  "DDP world size": ddp_world_size,
567
  "warmup_ratio": args.warmup_ratio,
568
  "warmdown_ratio": args.warmdown_ratio,