The Model Learns Back To Front

I lost a model this week. Not to a bug in the maths, and not to a bad idea, but to growing it too fast. Working out exactly how it died led me to a measurement I should have been taking all along, and that measurement says something I did not expect: for a long stretch of training, most of my model was doing literally nothing.

Why a model can be bigger and not better

My models grow while they train. They start as a single layer and gain more as they go, each new layer inserted at the front, initialised to be an exact mathematical no-op so it cannot disturb what is already working. Over a long run one lineage went from one layer to six.

More layers should mean more capability. That is the whole reason to add them. What I never did was check whether the layers I was adding were doing anything at all.

There is a reason that check is easy in this architecture and awkward in most others. Every intermediate state in my model can be read against the vocabulary directly, because the thing that turns a state into a prediction is the same table that turns a token into a state. So at any point mid-computation I can ask a well-posed question: what does this state currently resonate with, and how strongly? In a conventional transformer an intermediate activation has no privileged interpretation. Here it has one, and it is free to read.

Reading a half-formed model

Two numbers per checkpoint, taken at every step of the computation.

The first is how confident the state is about a single token. If it names one token at 100%, nothing has been computed; the state is just a copy of its input wearing the model's colours. The second is the effective number of candidates, which is two to the power of the entropy of that reading. One means pinned to a single token. Three means genuinely weighing three. Several hundred means the state has fallen off the vocabulary entirely and resolves to nothing useful.

Between them those two numbers separate the three things a state can be: a copy, a real computation, or noise. That distinction is the whole point. A state that has drifted somewhere meaningless looks busy and contributes nothing.

Two thirds of it was inert

I ran this on a snapshot of the six-layer model, taken from the run that later died. There are thirteen points to read: the raw embedding, then the state after each of the twelve passes.

pointconfidenceeffective candidates
embedding1.00001.00
layer 0, pass 01.00001.00
layer 0, pass 11.00001.00
layer 1, pass 01.00001.00
layer 1, pass 11.00001.00
layer 2, pass 00.99921.00
layer 2, pass 10.99991.00
layer 3, pass 00.99521.02
layer 3, pass 10.99161.03
layer 4, pass 00.97401.11
layer 4, pass 10.96221.20
layer 5, pass 00.478511.94
final0.312427.14

Four consecutive passes at 1.0000 to four decimal places. Not approximately a copy. A copy. Two entire layers, plus most of a third, contributing nothing measurable to anything.

All of the work is in the last layer. Its two passes take the state from naming one token to weighing twenty-seven, and everything before them is padding.

Growing added padding, not capability

The four-layer snapshot from earlier in the same run tells the more uncomfortable half of the story. Line its last four points up against the six-layer model's last four:

position from the endfour-layersix-layer
fourth from last0.9774 / 1.110.9740 / 1.11
third from last0.9592 / 1.220.9622 / 1.20
second from last0.4771 / 12.350.4785 / 11.94
final0.3135 / 27.030.3124 / 27.14

Identical to two decimal places, across all four.

Going from four layers to six did not make the model deeper in any sense that mattered. It reproduced exactly the same working window and prepended four more passes that did nothing. The part of the model that was actually computing stayed the same size. What grew was the number of weight matrices taking gradient, competing, and perturbing a stream they were not yet contributing to.

Counting the passes that carry real information:

modelpasses doing worktotal passes
six layers212
four layers28
current, two layers44

The two-layer model I am training now uses every pass it has. The six-layer model used a sixth of itself. By the measure that counts, the small one is the bigger model.

What that cost me

The six-layer run did not merely stagnate. It destroyed itself.

Loss began spiking into the thousands and clawing back, over and over, for about 43,000 rounds. Then in a single step every trainable parameter in the model became NaN: 764,288 values of 829,825. The 65,537 that survived were exactly the frozen numeric identity band, 1024 tokens times 64 fixed dimensions, and they survived only because nothing ever writes to them.

I had gradient clipping switched on the whole time. It did not fail to prevent this. It delivered it.

Clipping works by computing the size of the gradient and scaling it down if it is too big. The test is whether that size exceeds the limit. If any part of the gradient is NaN then the size is NaN, and a NaN is not greater than anything, so the test is false and the gradient is applied at full strength. And if the size overflows to infinity, the scale factor becomes limit divided by infinity, which is zero, and multiplying an infinite gradient by zero produces a fresh NaN that the usual skip-if-zero check does not catch either. The safety mechanism manufactured the failure it existed to prevent.

Both paths are now closed. The step is refused outright when the gradient size is not a finite number, so a bad batch is dropped and counted instead of being fatal, and the learning rate schedule no longer answers a loss spike by going to maximum.

But the deeper cause was not the arithmetic. It was that half the model had never crystallised, and I kept adding more.

The front layer finally moved

The current lineage is two layers and has been left alone. Its front layer is doing something no front layer of mine ever has.

modelfront layer, second pass
four-layer snapshot1.0000 confidence, 1.00 candidates
six-layer snapshot1.0000 confidence, 1.00 candidates
current two-layer0.8692 confidence, 1.46 candidates

One point zero zero zero zero is not a small number. It is zero information. The front layers of both older models were mathematically absent. The current one is carrying a genuine candidate set.

It is better than the best early pass those models ever had anywhere in their stacks, not just better than their front layers.

I want to be precise about what this is not. It is 1.46 candidates, not twelve. It has not moved since about round 99,000, so whatever formed, formed early and has been holding steady since rather than climbing. And it is nowhere near the point where adding another layer would be justified.

Where I was wrong along the way

Two mistakes are worth recording, because both produced confident wrong answers.

I measured how far into its context the model actually reads, using 25 sample windows, and got a clear result: still improving at the edge of the window, more context would help. Re-running the identical measurement with 220 windows reversed it completely. The model saturates at roughly 16 tokens and everything past that carries nothing measurable. The first run was not noisy-looking. It was confidently wrong, and I would have grown the context on the strength of it.

Then I tracked front-layer progress using the wrong quantity: how often its output names a different token from its input. By that measure the front layer had more than doubled over 223,000 rounds, which looked like steady progress. On the measure that separates computation from copying it had not moved at all. Both facts are true. The front layer increasingly picks a different single token, and a single token carries no alternatives to hand forward whichever token it is. I was counting motion and calling it work.

What I am doing about it

The rule I am training under now is that a layer has to finish before another one is allowed to start. Not a round count, not a schedule. The front layer's candidate count has to stop climbing, and then the pair has to settle together, and only then does a new front layer go in at zero to begin its own formation.

The model is at 320,000 rounds, two layers, 369,664 parameters. It answers in complete sentences now, with correct punctuation and contractions, and it has no idea what it is talking about across more than about fifty characters. Its context reach has not moved in three separate measurements. Whether patience is enough, or whether something about the training data has to change before a front layer will ever crystallise, is the thing this run is actually testing.

I will know which when the number stops being flat, in either direction.

← Back to Articles