Learning at Test Time

Dive into Deep Learning · §12.6

Learning at test time
one regression problem · a spectrum of solvers · the gate, derived · memories that are networks · tracking a drifting world

A thread from the attention chapter

Nadaraya–Watson regression: attention with a hand-picked kernel; one knob, the bandwidth \sigma — swept by hand, never learned.

f(x) = \sum_{i=1}^{n} \frac{\exp\big(-\tfrac{1}{2} ((x - x_i) w)^2\big)}{\sum_{j} \exp\big(-\tfrac{1}{2} ((x - x_j) w)^2\big)}\, y_i

The trap: y_i enters f(x_i) — driving w \to \infty zeroes the training error and learns nothing.

Fix: leave-one-out — predict each point from all the others.

Five epochs, one parameter

Leave-one-out keys and values, plain gradient descent on the scalar w:

epoch 1: leave-one-out loss 1.849, w = 1.266
epoch 2: leave-one-out loss 1.703, w = 1.541
epoch 3: leave-one-out loss 1.560, w = 1.781
epoch 4: leave-one-out loss 1.455, w = 1.975
epoch 5: leave-one-out loss 1.387, w = 2.132
learned bandwidth 1/w = 0.469
  • The loss falls every epoch; w climbs past its initialization at 1 — the learned bandwidth lands where the hand sweep pointed.

What learning sharpened

  • The region of large attention weights becomes sharper once the bandwidth is learned; the learned \sigma lands where the hand sweep pointed.
  • A regression estimator, tuned by gradient descent on the data it serves. Hold that shape.

One recipe

Memorize by regression, retrieve by evaluation (Wang, Shi & Fox 2025):

m_t = \mathop{\mathrm{argmin}}_{m \in \mathcal{M}} \frac{1}{2} \sum_{i \le t} \gamma_i^{(t)} \big\| \mathbf{v}_i - m(\mathbf{k}_i) \big\|^2, \qquad \mathbf{o}_t = m_t(\mathbf{q}_t)

Three choices fix a layer:

  • weights \gamma_i^{(t)} — which past counts
  • class \mathcal{M} — what associations are expressible
  • solver — how hard to fit, once per token

The reveal

model weights class solver
softmax attention query kernel nonparametric exact (Nadaraya–Watson)
linear attention uniform linear LS minus (\mathbf{K}^\top\mathbf{K})^{-1}
RetNet / GLA / Mamba-2 geometric decay linear weighted LS shortcut
DeltaNet uniform, gated linear one explicit SGD step
Longhorn uniform, gated linear one implicit step
Titans weight decay deep MLP SGD + momentum

Softmax attention is the Nadaraya–Watson estimator — ch. 10’s analogy was an identity. Linear attention’s capacity ceiling = the interference of the deleted covariance term (zero in expectation — variance, not bias).

Two loops: what learns when

Left — pretraining updates the outer parameters through every inner update. Right — at inference only the inner loop runs.

  • Inner loop: the state \mathbf{S}_t — fresh per sequence, adapts token by token, runs in every forward pass. No labels at inference: the targets are the sequence’s own values.
  • Outer loop: projections, gate networks, \mathbf{S}_0 — get gradients through the chain of inner updates; frozen at inference.
  • Applies verbatim to DeltaNet, Longhorn, Titans.

The spectrum, measured

One dataset, one feature space, one shared ridge objective — five solvers:

                solver  test MSE  objective  dist to opt
       Nadaraya-Watson     0.023         --        0.114
     online GD, 1 pass     0.151      9.372        0.372
   online GD, 5 passes     0.022      5.108        0.128
  online GD, 30 passes     0.008      4.542        0.031
           batch ridge     0.010      4.487        0.000
  • One online pass underfits; more passes fall monotonically toward the optimum — in objective and in distance to the batch fit.
  • Test error is not the objective: an unconverged iterate can edge past the optimum there (early stopping as a regularizer).
  • Nadaraya–Watson: a different estimator family — it fits nothing, it keeps every pair.

Three characters

Kernel smoother: faithful, ragged. One-pass delta: smooth, shallow. Batch solve: threads the noise. Every layer in the table is a point on this picture — computed once per token, forward-only.

Longhorn: the gate, derived

Implicit (proximal) step — solve the per-token subproblem exactly:

\mathbf{s}_t = \mathop{\mathrm{argmin}}_{\mathbf{s}} \|\mathbf{s} - \mathbf{s}_{t-1}\|^2 + \beta_t (\mathbf{s}^\top \mathbf{k}_t - v_t)^2

\mathbf{s}_t = (\mathbf{I} - \Delta_t \mathbf{k}_t \mathbf{k}_t^\top)\, \mathbf{s}_{t-1} + \Delta_t v_t \mathbf{k}_t, \qquad \Delta_t = \frac{\beta_t}{1 + \beta_t \mathbf{k}_t^\top \mathbf{k}_t}

  • Delta-rule shape; the form of \Delta_t is a theorem, its coefficient \beta_t still learned. And \Delta_t \mathbf{k}_t^\top \mathbf{k}_t < 1 — stable for any \beta_t.
  • Mamba parameterizes its gate; Longhorn derives the form and learns only the coefficient.

Closed form == argmin

200 random instances against the exact linear solve; 5 against brute-force gradient descent on the objective:

closed form vs linear solve, 200 instances: 4.53e-06
closed form vs gradient descent, 5 instances: 2.38e-07
  • Two thousand explicit gradient steps arrive where the implicit step lands in closed form.

Titans: surprise, momentum, forgetting

The memory is a module, adapted online during the forward pass (the inner loop; the full model learns its coefficients in the outer loop):

\mathbf{U}_t = \eta_t \mathbf{U}_{t-1} - \theta_t \nabla_{\mathbf{W}} \ell(\mathbf{W}_{t-1}; \mathbf{k}_t, \mathbf{v}_t), \qquad \mathbf{W}_t = (1 - \alpha_t) \mathbf{W}_{t-1} + \mathbf{U}_t

  • gradient = momentary surprise · momentum = past surprise · weight decay = forgetting
  • Linear memory, \eta = \alpha = 0: exactly the delta rule.
 overwrites per key  recall of latest
                  1             1.000
                  2             0.927
                  4             0.185
                  8             0.100

Momentum ⇒ a softer overwriter than pure delta — old surprise keeps writing superseded values.

A deep memory via autograd

d_mem, h_mem, num_pairs = 32, 128, 16
ks = jax.random.split(jax.random.key(3), 4)
k_pairs = jax.random.normal(ks[0], (num_pairs, d_mem))
k_pairs /= jnp.linalg.norm(k_pairs, axis=1, keepdims=True)
v_pairs = jax.random.normal(ks[1], (num_pairs, d_mem))
v_pairs /= jnp.linalg.norm(v_pairs, axis=1, keepdims=True)
order = jax.random.permutation(ks[2], jnp.tile(jnp.arange(num_pairs), 4))

params = {'W1': jax.random.normal(ks[3], (d_mem, h_mem)),  # Unit-var hidden
          'b1': jnp.zeros(h_mem),
          'W2': jnp.zeros((h_mem, d_mem)),  # Start empty: retrieve 0
          'b2': jnp.zeros(d_mem)}

def memory(params, k):
    hidden = jax.nn.gelu(k @ params['W1'] + params['b1'])
    return hidden @ params['W2'] + params['b2']

def recall_loss(params, k, v):
    return ((memory(params, k) - v)**2).sum()
grad_fn = jax.grad(recall_loss)

def retrieval_mse(params):
    return float(((memory(params, k_pairs) - v_pairs)**2).mean())

before = retrieval_mse(params)
theta, eta = 0.005, 0.5
def write(carry, t):
    params, velocity = carry
    g = grad_fn(params, k_pairs[t], v_pairs[t])     # Surprise
    velocity = jax.tree.map(lambda u, gg: eta * u - theta * gg, velocity, g)
    params = jax.tree.map(lambda p, u: p + u, params, velocity)
    return (params, velocity), None

velocity = jax.tree.map(jnp.zeros_like, params)
(params, _), _ = jax.lax.scan(write, (params, velocity), order)
after = retrieval_mse(params)
print(f'retrieval MSE: empty memory {before:.4f} -> after the stream '
      f'{after:.4f}')
assert after < before / 5
retrieval MSE: empty memory 0.0312 -> after the stream 0.0013

Regression that tracks

mean error over the last 500 steps: {'uniform LS': 0.99, 'decayed LS': 0.29, 'implicit step': 0.3}
  • Drifting truth \mathbf{w}^*_t: uniform LS goes stale — exact solver, right class, wrong weights.
  • Decayed LS tracks; the implicit step tracks with no solve at all. Decay = a belief about how fast the world changes.
  • Discount fixed by hand here (\gamma = 0.95); trained models emit it per token. Forgetting buys tracking under drift, costs efficiency on stationary stretches.

Where this leaves the chapter

  • One problem: memorize by weighted regression, retrieve at the query.
  • Softmax attention = Nadaraya–Watson; linear attention = LS with a term deleted; decay = the weighted cross-moment of weighted LS; delta = one SGD step; Longhorn = the implicit step, gate form derived; Titans = a deep memory, optimizer inside.
  • Forgetting is statistics, not housekeeping: stationary streams want uniform weights, drifting streams force decay.

Still missing: exact recall from an unbounded past. Hybrids — next.