Unit 2 · Optimization 1 · part a (CS 312 lecture 3, assignment 2)

Optimizers: noise, curvature and norms

~60 min read2 interactive widgets12 sealed predictions3 audit drills

The unit in one paragraph

An optimizer is four dials: a learning rate, a batch size, a preconditioner and momentum. Two simple models predict most of how they interact. The noisy quadratic treats the loss as a bowl with steep and flat directions and the gradient as a noisy measurement of its slope. It explains why the best learning rate grows with batch size and then stops growing, why larger batches eventually stop paying, and why momentum and preconditioning help mostly at large batch. The rotational picture of the weights starts from the fact that most weights in a normalized transformer only matter through their direction. Gradient steps then make their norms grow, weight decay pulls them back, and the two settle into an equilibrium where the learning rate and the weight decay act only through their product. That product explains measured results from CS 312 that look strange otherwise, such as why the right response to an eight times larger batch is eight times more weight decay. Hyperball fixes the norm by construction, so that the learning rate directly sets how far each weight turns. Twelve sealed predictions, most checked against CS 312’s measured d8 runs, and three audit drills.

In this unit

  1. What an optimizer is made of
  2. The noisy quadratic
  3. Batch size and the critical batch
  4. Momentum and preconditioning pay at large batch
  5. Where the quadratic stops
  6. Why weights grow
  7. One knob: the product ηλ
  8. Hyperball: fix the norm, keep the angle
  9. Audit drills
  10. Run it yourself
  11. Check your understanding

1. What an optimizer is made of

Plain stochastic gradient descent takes one step downhill on a minibatch: θ ← θ − η ∇ℓ(θ). Every optimizer in use is that update with four things changed:

AdamW, the d8 default, uses all four. Elementwise, for a weight matrix W with gradient g at step t:

m ← β1 m + (1 − β1) g       v ← β2 v + (1 − β2) g2     momentum, and a running second moment
U = [m / (1 − β1t)] / ( √[v / (1 − β2t)] + ε )     bias-corrected; dividing by √v is a diagonal preconditioner
W ← W − η U − η λ W     the step, then decay applied to the weights directly

The “W” stands for decoupled weight decay (Loshchilov and Hutter). Adding λ |W|²/2 to the loss instead would send the decay through the preconditioner, dividing it by √v and shrinking each coordinate by a different amount. AdamW shrinks every weight by the same factor 1 − ηλ per step. Hold on to that factor: it is the subject of sections 6 to 8. The d8 recipe uses β = (0.9, 0.95), ε = 10−8, peak η = 0.003, λ = 0.1, and exempts embeddings, normalization gains and biases from decay.

Why deep-learning optimizers are judged differently

Classical optimization theory asks how fast a method reaches a precise stationary point, on every function in some class. Training a language model asks for neither. Nobody runs a model to convergence; the goal is a good loose solution within a fixed budget, on one narrow family of functions. Adam is the standard example. Its original convergence proof contained an error, and Reddi and colleagues later built simple problems on which it does not converge. Practice did not change, because the guarantee was never what anyone relied on. CS 312’s stance follows from this. Convex intuition is a source of hypotheses, not a verdict. Build top-down models of the large-scale behaviour (how a recipe responds to learning rate, batch, scale), then reconcile them with bottom-up mechanisms. The rest of this unit does exactly that, twice.

Your move: multiply the loss by 10. What happens to an SGD step, and to an Adam step?

SGD’s gradient, and therefore its step, gets 10 times larger: the same η is now a 10 times larger learning rate, enough to diverge. Adam divides by the running √v, which also grows 10 times, so its step barely changes. The only exception is ε, which becomes relatively smaller. Adam is nearly invariant to the scale of the gradient; its step size per coordinate is set by η. Keep this in mind for section 6: a step whose size ignores the gradient’s scale is what makes weight norms matter.

2. The noisy quadratic

Zhang and colleagues (2019) asked how far one can get by pretending the loss is a quadratic bowl and the gradient is its slope plus Gaussian noise. Further than you would expect: their noisy quadratic model (NQM) predicted how the best learning rate, the effect of momentum and the benefit of preconditioning change with batch size in real networks. Its appeal is that everything about it can be solved exactly.

Rotate coordinates so that the curvature matrix H is diagonal, with eigenvalues hi. Then the loss is ½ Σ hi θi2 and the minibatch gradient is Hθ + ε, with noise ε ~ N(0, C/B): averaging B independent examples divides the variance by B. If C is diagonal in the same coordinates, every coordinate evolves on its own. With SGD at step size α:

θi ← (1 − αhi) θi − α εi,    εi ~ N(0, ci/B)
E[ℓi(t)] = (1 − αhi)2t E[ℓi(0)]  +  [1 − (1 − αhi)2t] · αci / (2B(2 − αhi))

The expected loss has two parts derived. The first is what is left of the start, shrinking by a factor (1 − αh)² per step. The second is a noise floor the run settles on, proportional to α/B. Three consequences follow, and between them they hold most of this unit:

  1. The steepest direction sets the speed limit. The factor |1 − αh| must stay below 1 in every direction, so α < 2/hmax. Past that the steep direction overshoots by more each step and the run diverges.
  2. The flattest direction sets the duration. It shrinks at a rate of about αhmin per step, so it needs on the order of 1/(αhmin) steps, and α cannot be raised to hurry it past the limit set by the steep direction.
  3. The noise floor costs α/B. A larger learning rate finishes the flat direction sooner and parks the run higher. A larger batch lowers the floor, but at a fixed data budget it also means fewer steps.
Your move: derive the noise floor from the update rule.

Square the update and take expectations; the noise is independent of θ, so the cross term vanishes: v′ = (1 − αh)² v + α²c/B, where v = E[θ²]. At the fixed point v = α²c / (B(1 − (1 − αh)²)) = αc / (B h (2 − αh)). The loss is ½hv = αc / (2B(2 − αh)). It depends on α and B only through α/B as long as αh is small, which is the seed of the linear scaling rule in section 3.

CS 312’s assignment 2 uses the smallest interesting case: two coordinates with H = diag(1, 10), noise covariance I (the same noise in both directions), a fixed budget of N = 8,192 examples (so N/B steps), and a random start, w1 ~ N(0, 1) and w2 ~ N(0, 0.1). The widget below is that toy. For SGD, momentum and the preconditioned variant the expected loss is computed exactly, by carrying the second moments through every step. Adam has no closed form, so it is simulated. Every view also shows the average of 64 seeded simulated runs, so you can see the exact curve and the simulation agree.

The noisy quadratic, live

H = diag(1, 10), gradient noise N(0, I/B), 8,192 examples, constant step size. Exact where a closed form exists; 64 seeded runs otherwise.

This widget needs JavaScript.

Things to try, in this order:

3. Batch size and the critical batch

Hold the data budget fixed at 8,192 examples and ask how the best SGD step size changes with the batch. Predict before switching the widget to its sweep view.

In the toy above, with plain SGD and the step size tuned separately at each batch size, the batch goes from 16 to 32 (so from 512 steps to 256). By what factor does the best step size change?

  1. It stays about the same: the curvature has not changed
  2. About ×√2
  3. About ×2
  4. About ×4

About ×2 (exactly 0.00944 → 0.0186, a factor of 1.97) derived. While αh is small, (1 − αh)2T ≈ e−2αhT with T = N/B, so the leftover depends on α/B, and so does the noise floor αc/(4B). Double B and double α and the expected loss after the same number of examples is unchanged. This is the linear scaling rule, which Goyal and colleagues used to train ImageNet in an hour.

Computed exactly from the closed form in this page; you can check it in the sweep view.

The argument has an expiry date. It needs αhmax to be small, and the limit α < 2/hmax does not move with the batch. Once the best step size gets near that limit, a larger batch still lowers the noise but can no longer buy a proportionally larger step, and the flat direction gets fewer steps to finish. Past that point a larger batch just wastes data. McCandlish and colleagues called the turning point the critical batch size; Zhang and colleagues showed the NQM reproduces it, and that it depends on the optimizer.

Fit the linear rule η* = c·B to the toy’s tuned SGD step sizes at B = 1 to 64. They fit it almost perfectly. Now use the rule at B = 512 (16 steps). What happens at the extrapolated step size?

  1. Within 10% of the best loss at B = 512
  2. About twice the best loss
  3. The run diverges
  4. Better than the tuned step: the rule extrapolates past what a grid finds

It diverges derived. The rule gives η ≈ 0.000589 × 512 ≈ 0.30, above the stability limit 2/hmax = 0.2. The tuned step at B = 512 is 0.174, and even then the best loss is 5.7 times the B = 1 value. A rule fitted where its assumption holds says nothing about where the assumption breaks, and nothing in the fit warns you. Problem 3.1 of the assignment makes you find this range yourself.

Computed exactly from the closed form in this page.

Switch the widget to tune η at every batch size. The left panel shows the best step size against B on log axes: slope 1 for SGD until it bends toward the stability limit. The right panel shows the best loss after tuning: flat while the linear rule holds, then rising. SGD’s best loss is up 9% at B = 64, 22% at B = 128 and 5.7 times at B = 512 derived. In this toy the critical batch is around 64 to 128 examples.

Adam scales differently

For adaptive methods the analogous small-step argument suggests η* ∝ √B instead of ∝ B (the square-root rule of Malladi and colleagues). Real language models follow neither rule cleanly, and published scaling rules for the optimal learning rate disagree with each other; the assignment opens with a figure collecting them, from the Step Law paper. Assignment 2 has you measure the exponent for Adam in the toy, then in d8 at batch sizes 8 to 256. Section 7 shows that for AdamW the cleanest thing to scale with batch is not the learning rate alone.

4. Momentum and preconditioning pay at large batch

Momentum. With s ← μs + g and θ ← θ − ηs, a run that takes small steps behaves like SGD with step size η/(1 − μ): the sum of agreeing gradients is just a larger step. Once the step size is tuned, that buys nothing. The difference shows up when the stability limit binds. Heavy-ball momentum stays stable up to ηh < 2(1 + μ), so its effective step η/(1 − μ) can reach 2(1 + μ)/((1 − μ)hmax): 38/hmax at μ = 0.9, against SGD’s 2/hmax derived. The flat direction gets large steps while the steep one oscillates but does not blow up. Small batches need small steps anyway, because the noise floor is high, so the extra headroom is useless there. Large batches have a low floor and can use it.

Preconditioning. Zhang and colleagues model it as stepping with H−p: each direction gets step ηh−p. At p = ½ the toy’s curvature spread shrinks from 10 to √10, so the steep direction stops holding the flat one back. Adam’s division by √v is a rough, noisy version of this, and in their experiments Adam and K-FAC raised the critical batch well above SGD’s.

The sweep view puts numbers on both derived. Tuned momentum (μ and η both tuned) beats tuned SGD by 1.02× at B = 1, 1.7× at B = 16 and 7.3× at B = 512. Preconditioning beats it by 1.46× at B = 1 and 7.7× at B = 512. In the toy preconditioning helps even at batch 1, which differs from the paper. The reason is that the assignment’s noise is the same in both directions, so the preconditioner also cuts the noise injected along the steep one; Zhang and colleagues assumed the noise covariance equals the curvature, and under that assumption the small-batch gain disappears. One more trap: with μ fixed at 0.9 instead of tuned, momentum is worse than SGD at B ≥ 128 in the toy. Sixteen to sixty-four steps are too few for a memory that spans about ten of them. “Momentum helps at large batch” assumes enough steps for it to act.

CS 312 ran the d8 version (quiz 2, building on assignment problem 3.2). At 614.4M tokens and two batch sizes, each at its own tuned learning rate and weight decay, only β1 of AdamW changed: 0, 0.9 or 0.98, with β2 = 0.95. At B = 8 (η = 0.00075, λ = 0.1) the default β1 = 0.9 reached 2.9366; at B = 256 (η = 0.0015, λ = 1.944) it reached 2.9682 measured.

At B = 8, rank the three runs (β1 = 0, 0.9, 0.98) by final validation loss, best first.

  1. 0.98, then 0.9, then 0
  2. 0, then 0.9, then 0.98
  3. 0, then 0.98, then 0.9
  4. 0.9, then 0.98, then 0

0.98 < 0.9 < 0 measured. At B = 8 the momentum curve is nearly flat, so the order between 0.9 and 0.98 is the hard part; removing momentum entirely still costs a little. The NQM says the small-batch effect of momentum should be small, not that more momentum should be worse.

CS 312 quiz 2, question 4, answer slides (Fall 2026).

At B = 256, the same ranking.

  1. 0.98, then 0.9, then 0
  2. 0, then 0.9, then 0.98
  3. 0, then 0.98, then 0.9
  4. 0.9, then 0.98, then 0

0.9 < 0.98 < 0 measured. At large batch the curve over β1 is sharp: no momentum is much worse, and too much is also worse. Fewer steps leave less room for a long memory, as in the toy.

CS 312 quiz 2, question 4, answer slides (Fall 2026).

How much does removing momentum (β1 = 0 instead of 0.9) cost in final validation loss, at each batch size?

  1. Under 0.01 at both
  2. About 0.03 at B = 8, about 0.25 at B = 256
  3. About 0.25 at B = 8, about 0.03 at B = 256
  4. About 0.1 at both

0.0276 at B = 8 and 0.2503 at B = 256 measured: about nine times larger at the larger batch, the direction the NQM predicts. Note the design: each batch kept its own tuned η and λ while β1 changed, so the β1 = 0 runs were not retuned. Removing momentum changes the effective step size, so part of the 0.25 may be a learning-rate mismatch rather than the absence of momentum as such. The assignment asks you to compare this with the toy, where η was retuned for every μ.

CS 312 quiz 2, question 4 (b); differences computed from the course’s measured losses.

5. Where the quadratic stops

The NQM is the workhorse of this unit because it is exactly solvable and often points the right way. It is also wrong about several things that matter, and knowing where is part of using it:

The working rule: trust the NQM for the direction of an effect and for which regime you are in, and measure the size.

6. Why weights grow

CS 312’s first quiz contained a question that looks like bookkeeping. Four d8 runs cross the learning-rate schedule (linear decay or constant) with weight decay (0.1 or 0). Every step, each run logs the L2 norm of all its parameters and the L2 norm of its gradient before clipping. Predict before reading on.

At the end of training, which runs have a parameter norm noticeably (3–15%) below the highest value it reached during the run? The others end within 3% of their peak.

  1. All four: norms always come down as training settles
  2. Both runs with weight decay 0.1
  3. Only linear decay with weight decay 0.1
  4. None: every run ends at its peak

Only linear decay with weight decay 0.1 measured; the other three end within 3% of their peak. Without weight decay nothing pulls the norm down, so it ends at its maximum. With weight decay and a constant learning rate it reaches an equilibrium and stays there. Only when the learning rate falls does the equilibrium itself move down, and the norm follows it. The rest of this section and the next explain why.

CS 312 quiz 1, question 6 (a), answer slides (Fall 2026).

In which runs does the gradient norm before clipping at least double over training (median of the last 10% of steps against the first 10%)?

  1. The two runs without weight decay
  2. The two linear-decay runs: the gradient norm climbs as the learning rate falls
  3. None of the four
  4. All four

None of them measured. Defazio (2025) reported gradient norms that rise sharply near the end of training with weight decay and a decaying learning rate, and proposed a fix (AdamC). The d8 runs did not show it at this scale and length. The answer slides note that the gradient norm seemed driven more by weight decay than by the schedule.

CS 312 quiz 1, question 6 (b), answer slides (Fall 2026).

Scale invariance

Most weight matrices in a transformer with RMSNorm feed, directly or a few operations later, into a normalization that divides out their scale. QK-norm normalizes queries and keys; the pre-norm before each block normalizes the residual stream. For such a weight, multiplying it by any c > 0 leaves the network’s output unchanged, or nearly: L(cw) = L(w). Two facts follow by differentiating that identity derived:

Now take a step u orthogonal to w. By Pythagoras, |w + u|² = |w|² + |u|²: every step makes the norm grow, whichever way it points. A larger norm means the same step turns the weight by a smaller angle, and the angle is all the loss cares about. For SGD the effect compounds, because the gradient itself shrinks like 1/|w|: the effective learning rate is η/|w|² (van Laarhoven, 2017). Without weight decay the effective learning rate decays on its own, on a schedule nobody chose and nobody logs. Weight decay multiplies the norm by 1 − ηλ every step, pulling it back. The question is where the two balance.

7. One knob: the product ηλ

Four more predictions first, because the next derivation gives them away. All four are from CS 312’s second quiz, on d8.

The first two use a 3 × 3 grid of peak learning rates {0.0015, 0.003, 0.006} and weight decays {0.1, 0.2, 0.4}, at 1.2288B tokens with a cosine schedule. The best cell was η = 0.003, λ = 0.2, with loss 2.8354 measured.

Three other cells of that grid: A (η = 0.006, λ = 0.1), C (η = 0.006, λ = 0.4) and D (η = 0.0015, λ = 0.1). Rank them by loss, best first.

  1. D, A, C: the lowest learning rate is the safest
  2. A, D, C
  3. A, C, D
  4. C, A, D: the most regularization wins at this budget

A, then D, then C measured (the full measured order of the six off-optimum cells was A < B < F < E < D < C). Look at the products ηλ: A has 6×10−4, the same as the best cell, and is the closest to it, although its learning rate and weight decay are each off by a factor of two. D’s product is four times too small and C’s four times too large. Both are off by the same factor, and C is worse; with the learning rate also doubled, C is the one pushing toward instability.

CS 312 quiz 2, question 2 (a), answer slides (Fall 2026); our three-cell version of the question.

How far above the best cell (2.8354) is C?

  1. Less than 0.005
  2. 0.005 to 0.015
  3. 0.015 to 0.025
  4. 0.025 or more

About 0.032 measured. CS 312’s rule of thumb from the assignment’s fits is a quadratic penalty in how far the product is off: about 0.007 × (log2 of the factor)². Off by 4 = 2², that is 0.007 × 4 ≈ 0.028 derived.

CS 312 quiz 2, question 2 (b), answer slides (Fall 2026).

The next two start from the default d8 at 614.4M tokens, where the best pair at B = 64 is η = 0.003, λ = 0.2 (loss 2.9178) measured. The batch becomes 512: the same tokens in eight times fewer steps. Five recipes: A keeps both; B multiplies η by √8; C multiplies η by 8; D multiplies λ by 8; E multiplies both by √8.

At B = 512, which recipe gives the lowest loss?

  1. A: keep both; Adam is batch-invariant enough
  2. B: η × √8, the square-root rule
  3. C: η × 8, the linear rule
  4. D: λ × 8
  5. E: both × √8

D, eight times the weight decay measured. C, D and E all multiply the product ηλ by 8; D does it without touching the learning rate, which the noisy quadratic says cannot grow without limit. The answer slides summarize the assignment’s batch experiments this way: scaling weight decay with batch is predictable, scaling the learning rate tapers off.

CS 312 quiz 2, question 7 (a), answer slides (Fall 2026).

How much worse is recipe A (keeping the batch-64 pair) than the best recipe?

  1. Less than 0.02
  2. 0.02 to 0.05
  3. 0.05 to 0.15
  4. 0.15 or more

About 0.106 measured. The answer slides’ estimate: each doubling the product is off costs about 0.01 × (doublings)², and 8 is three doublings, so 0.01 × 9 ≈ 0.09 derived.

CS 312 quiz 2, question 7 (b), answer slides (Fall 2026).

The equilibrium

Here is why the product is the knob. Take a scale-invariant weight w with d entries, trained with AdamW. Assume:

  1. each step u is orthogonal to w (scale invariance);
  2. its size is roughly constant, |u| ≈ ηρ√d, where ρ is the per-coordinate RMS of Adam’s update (Adam normalizes, so ρ does not track the gradient’s scale);
  3. successive steps point in roughly unrelated directions, so they add like a random walk, not coherently;
  4. ηλ ≪ 1, and the run is long compared with 1/(2ηλ) steps.

Each step shrinks w by 1 − ηλ and adds an orthogonal |u|:

|w′|² = (1 − ηλ)² |w|² + η²ρ²d
equilibrium:  |w|² = η²ρ²d / (1 − (1 − ηλ)²) ≈ ηρ²d / (2λ)
angle turned per step:  |u| / |w| ≈ ηρ√d / √(ηρ²d / 2λ) = √(2ηλ)

At equilibrium the angle each weight turns per step is about √(2ηλ) derived. It depends on η and λ only through their product, and not on ρ or d. Since the loss only sees the direction, the product is the effective learning rate; η alone sets only the equilibrium norm. Kosson and colleagues (2024) call this rotational equilibrium; the same algebra with SGD (gradient ∝ 1/|w|) gives the same √(2ηλ). The approach to equilibrium takes about 1/(2ηλ) steps. For d8’s defaults, 2ηλ = 6×10−4, so that is about 1,700 of its 9,375 steps, and the equilibrium angle is about 0.024 radians, 1.4° per step derived. Real updates are only approximately orthogonal and uncorrelated, so read these as orders of magnitude.

Rotational equilibrium in the plane

A weight w in two dimensions whose loss depends only on its angle. Each step has fixed size η, is at right angles to w, and points toward the best direction when a noisy sign says so (an Adam-like normalized step). Exact simulation, 3,000 steps, seeded.

This widget needs JavaScript.

In the toy the step size is exactly constant, so the equilibrium is exact: |w|² = η/(λ(2 − ηλ)), and the angle per step is a function of ηλ alone derived. Things to try:

Reading the measured results

The grid. If only ηλ mattered, the loss surface over (log η, log λ) would be a valley along lines of constant product. The measured grid is close to that: the cells that keep the best product (A and B) are the best of the rest, and penalties grow with how far the product is off. Not exactly, because η also matters on its own: it sets the step size of the parameters that are not scale-invariant (embeddings, gains, the readout), and the stability limit from section 2 still applies. That is why C, with η doubled as well, is worse than D.

The batch. At a fixed token budget, B = 512 means eight times fewer steps. If the right amount of rotation over the whole run is what matters, each step must rotate more, and the timescale 1/(ηλ) must shrink eight times when measured in steps. Wang and Aitchison read AdamW as an exponential moving average of updates with that timescale. Bergsma and colleagues (Power Lines) found that the best timescale, expressed as a fraction of the training data, B/(ηλD), stays roughly constant, which makes the right ηλ proportional to B. Recipes C, D and E all satisfy that. D wins because it gets the whole factor from λ, which has no stability limit, while C puts it all into η, which does. Quiz 2’s B = 256 setting in section 4 (η = 0.0015, λ = 1.944) is this rule applied.

Your move: the batch doubles in the middle of a run. Which single change keeps the rotation per token the same, and why not just raise η?

Double λ. After the switch there are half as many steps per token, so each step must rotate √2 times more: √(2ηλ) × √2 means ηλ × 2. Doubling η also doubles the product, but it doubles the step size of the parameters that are not scale-invariant too, and moves you toward the stability limit. Doubling λ changes only the equilibrium. Assignment 2 has a worked example question on exactly this switch, with five policies to rank; try it before reading their answer.

8. Hyperball: fix the norm, keep the angle

If the learning rate and weight decay matter mostly through the norm equilibrium they produce, why not set the norm directly? Hyperball (Wen and colleagues, 2026), used in assignment 2, does this for every linear-layer weight matrix. Take Adam’s update direction U, scale it relative to the weight, step, then project back to the weight’s initial Frobenius norm R = |W0|F:

W̃ = W − η |W|F U / |U|F      W ← R · W̃ / |W̃|F

No weight decay is needed, because the norm cannot drift. The relative step is η on every step, so the angle turned per step is about arctan η, whatever happened earlier in the run. The learning rate becomes a number with a meaning: the fraction of the weight’s norm to move per step. Switch the widget above to Hyperball to see it: the radius never changes and the angle per step stays fixed at arctan η.

Two subtleties the lecture flags. Not every weight should be norm-constrained: the readout’s scale encodes the model’s confidence, and embeddings may use their norms, so the course applies Hyperball to the internal matrices and the readout, while embeddings and normalization gains use Adam at 0.1041η. And the idea has relatives: weight normalization, steps on the sphere or on the Stiefel manifold, column-wise norms, ball projection. Wen and colleagues report lower loss and norm control by construction; the open question in the assignment is whether it also makes the best learning rate scale more predictably.

CS 312 fitted Hyperball’s optimal peak learning rate on d8 (weight decay off) at four token budgets. Read off their plot, the fitted optima are roughly 0.014, 0.013, 0.012 and 0.010 at 0.15B, 0.31B, 0.61B and 1.23B tokens measured (approximate, read from a figure). Which interval contains the fitted optimum at 2.46B tokens?

  1. 0.0075 or more
  2. 0.0055 to 0.0075
  3. 0.004 to 0.0055
  4. Less than 0.004

About 0.008 measured. The trend continued. A straight line in log–log through the four points gives about 0.009 derived; the last two alone give about 0.008. The answer slides call it an easy question for that reason: follow the line. Whether AdamW’s ladder in assignment problem 1 is as regular is exactly what the assignment asks you to find out.

CS 312 quiz 2, question 3, answer slides (Fall 2026).

9. Audit drills

Three fictional research logs, each written like an AI research agent’s notes. Each one breaks a rule from this unit while sounding reasonable. Tick every objection you would raise, then check. The director’s checklist from unit 0 applies throughout.

[agent] Project: chess-move model, 60M params. Baseline B=128, AdamW lr 2e-3, wd 0.1, cosine schedule (config: total_steps=37,500, warmup=750), 4.9B tokens, val 1.874. [agent] Throughput: B=256 is 1.7x faster per token on our GPUs. Switched batch to 256, everything else from the same config. 4.9B tokens = 18,750 steps. [agent] Result: val 1.906 (+0.032). Seed spread on this model is ~0.004 (3 seeds), so the gap is real. [agent] Conclusion: larger batches hurt this model, consistent with the generalization gap of large-batch training. Reverting to B=128 and dropping the batch-size line of work.

Which objections would you raise?

Two of the checklist’s questions fail here: was each arm tuned (no), and were the runs compared after the decay (no, and nobody noticed because the config hid it). The repair: express the schedule in tokens, rerun B=256 at λ × 2 and at η × √2 (two runs), and compare after the decay. The self-review checked whether the gap was larger than the noise, which it was, and stopped there.

[agent] Project: small code model, 120M params, AdamW baseline tuned over lr {5e-4, 1e-3, 2e-3} x wd {0.05, 0.1, 0.2}: best lr 1e-3, wd 0.1, val 1.412. [agent] Trying Lion (sign of an interpolated momentum, betas 0.9/0.99). Same lr 1e-3, wd 0.1, schedule, data order. 1 seed. [agent] Lion: loss spikes at step 1,800 and 4,100, recovers; final val 1.561. [agent] Lion is 0.149 worse. Seed spread ~0.005, so ~30 sigma. [agent] Conclusion: Lion is not suited to code data. Closing the ticket.

Which objections would you raise?

Checklist question 1 (was each arm tuned) fails in the most common way: the baseline got a 3 × 3 grid and the challenger got the baseline’s winner. Question 5 would have caught it too: one Lion run at lr 3e-4 would likely have changed the picture. The repair is a Lion grid around lr 1e-4 to 3e-4 with wd 0.3 to 1.0, the same size as AdamW’s.

[agent] Project: symbolic-music model (MIDI tokens), 45M params, AdamW lr 3e-3, wd 0.1 applied to ALL params including RMSNorm gains. Baseline val 1.208 (3 seeds: 1.205 / 1.208 / 1.211). [agent] Cleanup "bridge" run toward the new recipe: (1) exclude norm gains and biases from weight decay, (2) warmup 1% -> 3%. Seed 0. [agent] Result: val 1.248. Delta +0.040, within the noise of a single seed. Adopting as the new baseline so later changes compare against it.

Which objections would you raise?

The worst move in this log is not the bundling. It is declaring the result noise without looking at the noise, then making the regression the new reference point. The repair: rerun the baseline from the same commit; run the two changes separately at seeds 0 and 1; adopt only a version that is no worse than the old baseline within its seed spread.

10. Run it yourself

Not run by us

Nothing on this page was run on a GPU for this companion. The measured numbers are CS 312’s; the toy numbers are computed by this page’s widgets. The commands below are the ones the assignment handout gives, on the a2_release branch, with the Modal setup from unit 0.

Lab 2aAssignment 2, problems 1–3
  1. Problems 1 and 2 need no new runs to start. The course published its sweeps (learning rate against token budget, Hyperball, the learning-rate × weight-decay grid). List them with links, or read the measurements offline without --links:
    uv run python -m experiments.a2.provided_sweeps --part P1a --links
    Replace P1a with P1b, P1d, P1e or P2a. Fit the quadratic in log learning rate yourself, and make the extrapolation in 1 (b) before you look at the larger budgets.
  2. Problem 3.1 runs on a CPU. Write your own noisy-quadratic simulation (at least 512 samples per point, as the handout asks), then check it against this page’s exact curves. The widget’s math core is assets/u2a.js and loads in node: require('./u2a.js').sgdFinal(eta, B, 0, 8192 / B). Adam and RMSProp are where your simulation does the work.
  3. Problem 3.2 is the expensive one. About 48 d8 runs at 614.4M tokens across batch sizes 8 to 256, launched with the starter’s launch_training_jobs. At roughly 15 minutes per run on an H100 for B = 64, that is at least 12 GPU-hours, more because small batches run slower. Budget it before launching, and run the unit 0 harness check first.

Check your understanding

In the noisy quadratic, what limits the step size and what limits how fast the run finishes?

The steepest direction limits the step size: α < 2/hmax, or it diverges. The flattest direction limits the duration: it needs about 1/(αhmin) steps. The gap between the two is why preconditioning, which narrows the curvature spread, helps.

Why does the best SGD learning rate grow linearly with batch size, and why does that stop?

For small steps, both the leftover from the start and the noise floor depend on α/B at a fixed number of examples, so doubling both leaves the outcome unchanged. It stops when α approaches 2/hmax: the steep direction caps the step, and beyond that larger batches only reduce the number of steps. That turning point is the critical batch.

Why does momentum help at large batch but not at small batch, according to the NQM?

At small steps momentum is SGD with step η/(1 − μ), which tuning matches. Small batches need small steps because of the noise floor. Large batches can use large steps, and momentum stays stable up to ηh < 2(1 + μ), so its effective step can exceed SGD’s 2/hmax. Measured on d8: removing momentum cost about 0.03 at B = 8 and 0.25 at B = 256.

Why do scale-invariant weights grow under gradient descent?

Scale invariance makes the gradient orthogonal to the weight, so every step adds its squared length to the squared norm (Pythagoras). Nothing removes it unless weight decay does.

At equilibrium under AdamW, what sets the angle a scale-invariant weight turns per step, and what does η alone set?

The angle is about √(2ηλ): the product. η alone sets the equilibrium norm, |w|² ≈ ηρ²d/(2λ), and the step size of the parameters that are not scale-invariant.

A batch goes from 64 to 512 at a fixed token budget. Which change did CS 312 measure as best, and what does keeping the old settings cost?

Multiplying weight decay by 8, which multiplies ηλ by 8 (the Power Lines rule ηλ ∝ B) without pushing the learning rate toward instability. Keeping the batch-64 pair cost about 0.106.

What does Hyperball change, and what does its learning rate mean?

It scales each matrix’s Adam step relative to the weight’s norm and projects back to the initial norm, with no weight decay. The norm cannot drift, so η is the relative step per update, about the angle turned per step.

Sources