InterviewPrepKit

Home / Cheat Sheet / Machine Learning

Cheat sheet

Training and Optimization

Read the full lesson →

Training speed is set by the condition number kappa, the ratio of the sharpest to the flattest curvature of the loss surface: the learning rate is capped by the sharp direction, progress is paced by the flat one, and every technique here attacks that ratio.

The central mechanism

  • Loss surface curvature differs by direction; kappa = 1 is a round bowl, high kappa is a ravine.
  • Max stable learning rate is 2/lambda_max (lambda_max = sharpest curvature). Exceed it and the sharp coordinate diverges regardless of the rest.
  • Progress is bounded below by the flattest direction, so cost scales with kappa.
  • Two routes to shrink kappa: reshape the surface (RMSProp, normalization, good init) or use history (momentum).

Optimizer family

flowchart LR
    SGD["SGD"] --> MOM["Momentum"]
    SGD --> RMS["RMSProp"]
    MOM --> ADAM["Adam"]
    RMS --> ADAM
    ADAM --> ADAMW["AdamW"]
    style ADAM fill:#2d6a4f,color:#fff
MethodUpdate ideaFixesSpeedup
SGDw -= eta*gnothingbaseline
MomentumEMA of g, beta=0.9ravines (over time)kappa -> sqrt(kappa)
RMSPropdivide by sqrt(EMA of g^2), rho=0.9scale mismatch (per param)scale-free step ~eta
Adamboth, plus bias correctionbothdefault optimizer
AdamWdecay applied outside sqrt(v)broken L2-in-Adamcorrect regularization
  • Momentum amplifies consistent gradients 1/(1-beta)=10x, attenuates oscillating ones 1/(1+beta)=0.53x; it silently multiplies effective LR by 1/(1-beta), so lower eta when enabling it.
  • Adam defaults: beta_1=0.9 (~last 10 grads), beta_2=0.999 (~last 1000), eps=1e-8. Bias correction m/(1-beta_1^t); distortion peaks ~6.5x near step 12, still 26% at step 1000.
  • Adam stores m+v (2N) vs momentum’s 1N.

Batch size

  • Gradient noise falls as sigma/sqrt(B); cost rises as B. Quadrupling B quadruples compute per step but only halves noise.
  • Helps while the device is underused; does nothing once saturated; hurts too small (kernel-launch bound, erratic) or too large (loses exploration noise, sharper minima).
  • LR scaling: linear (eta~B) with SGD, sqrt (eta~sqrt(B)) with Adam. Linear scaling always ships with warmup.

Schedules, clipping, init

  • Warmup (always with Adam, 500-4000 steps ~1/(1-beta_2)): v is noisy from few samples early, and one oversized step saturates attention softmax (dead gradient). Use pre-LN.
  • Decay: cosine to ~0.1*eta_max if budget known; else constant then step down on val plateau. Anneal to 0.1*eta_max, not 0.
  • Gradient clipping: if ||g||_2 > c: g *= c/||g||_2. Clip by global norm (preserves direction). Order: unscale -> clip -> step. Still needed under Adam because a spike poisons v (~11x for a 100x spike) freezing steps for thousands of iterations.
  • Init: keep per-layer gain k = n_in*Var(w) = 1, else variance goes k^L. Xavier Var(w)=2/(n_in+n_out) for tanh; He Var(w)=2/n_in for ReLU (extra sqrt(2) since ReLU zeros half). Residual branches: scale by 1/sqrt(2L). Zero/constant init fails by symmetry.

Regularization

  • L2 = weight decay under SGD only; under Adam they differ (L2 rides the gradient through sqrt(v)), so use AdamW. Never decay biases or LayerNorm gains.
  • L2 keeps high-curvature directions, deletes the ones data didn’t constrain. L1 gives sparsity (constant lambda*sign(w) pull to exactly zero).
  • Dropout: keep prob p, inverted (x*mask/p at train) so eval() is a no-op. Forgetting model.eval() leaves dropout on. Dropout + downstream BatchNorm interact badly (variance shift 1/p).
  • Early stopping ≈ L2: lambda_effective ~ 1/(eta*t); don’t tune both.
  • Label smoothing caps the otherwise-infinite logit gap, improving calibration.
  • Regularization narrows the train/val gap; it cannot lower the val level. Hurts when underfitting.

Diagnosis

Overfit a single batch (8 samples, no shuffle/aug/dropout/decay) to ~0 loss first. If it can’t, it’s a wiring bug (labels, loss axis, requires_grad, zero_grad, eta=0). Then read the loss-curve shape:

SymptomMechanismFix
Flat at ln(C)LR too low, dead ReLUs, or k<1 initLR range test; He init
Rises then naneta > 2/lambda_maxhalve eta; clip at 1.0
Spikes, never recoversoutlier poisoned Adam’s vclip before step; restart checkpoint
Train down, val upoverfittingdata/aug, then decay/dropout
Val below traindropout/BN accountingre-measure train in eval()
Val ~0 from epoch 1leakagesplit by entity
Bigger batch, no speedupdevice already saturatedstop growing B

Scale

  • Mixed precision: 16-bit math + fp32 master weights. fp16 needs loss scaling (S=1024, unscale before step) as grads near 1e-7 underflow; bf16 avoids it (fp32-range exponent). Saves activations and matmul time, not optimizer state.
  • Gradient accumulation: (loss/ACCUM).backward(); missing the divide is a silent ACCUMx LR. BatchNorm can’t be emulated this way.
  • Parallelism: data parallel if one replica fits; else shard optimizer state (ZeRO/FSDP), a layer (tensor parallel, needs NVLink), or depth (pipeline, pay the bubble (P-1)/(m+P-1)).
Want the full picture? The lesson has the derivations, worked examples, and diagrams this card compresses into bullets. Read the full lesson →
Report a bug