Published on

What Are Looped Transformers? A Technical Deep Dive

A looped transformer applies the same block of layers to a token more than once. Instead of stacking L distinct layers and running each exactly once, you keep a small stack of shared layers and run it in a loop: four real layers applied thirty-two times give you 132 layers of computation out of the parameters of eight. The idea goes back to the Universal Transformer in 2018, and the modern name for it is recurrent depth.

What makes it interesting is that the loop count is not baked into the checkpoint. In an ordinary transformer, depth is a property of the weight file — you ship eighty layers, and every prompt gets eighty layers. In a looped model the number of passes, r, is an argument you pass at call time, so the same weights can be told to think harder about a hard question than an easy one. And the extra thinking happens inside the hidden state, between emitted tokens, rather than in text anyone can read.

Which is why, on 2 September 2026, this became an argument about safety. The Information reported that OpenAI's Astra uses recurrent depth — the same weights applied several times over — and that this makes some of its internal reasoning harder to read. Astra shipped as a preview the next day, went generally available on the fourth, and by then the argument had sorted itself into two camps that were not really talking to each other.

One camp read it as a redline crossed. Ryan Greenblatt: Astra "fundamentally doesn't have a fully monitorable chain of thought in the same way as past models. Very very bad news." Steven Adler, until recently on OpenAI's safety staff, called it a violated redline. The other camp read it as nothing at all. @nrehiew_: a looped transformer has "zero impact, because it is simply spending more compute per token." Sebastian Raschka called it a tiny architectural tweak and noted, correctly, that reusing layers does not by itself suppress a visible chain of thought.

Then Jakub Pachocki posted, which is unusual for a chief scientist mid-news-cycle, and said something better than either camp: the depth of Astra's computation graph is within a factor of two of GPT-4 — and, separately, that chain-of-thought monitoring "is fragile and unfortunately trending in a negative direction, for reasons not contingent on architecture changes."

The architecture claim rests on one anonymous source. No technical report, no code, no patent, nobody outside OpenAI in a position to check it. So I stopped reading the argument and read the architecture, which — unlike Astra — is documented in detail, mostly by people who published long before any of this was a story. Thirteen papers later, what a loop actually buys turns out to be narrower than the alarmed reading requires and stranger than the deflationary one admits.

This post is the mechanical version: what the forward pass does line by line, how the test-time dial is manufactured during training, what the loop costs in FLOPs and KV cache with the arithmetic shown, what the literature establishes, and whether this is the thing that pushes models further. Every mechanism is drawn out as a diagram.


TL;DR

  • Section 1 is the whole idea with no notation at all — four animated pictures showing what changes, why it makes answers better, and what it costs. Everything after that is the engineering. Symbols are collected in an appendix at the end.
  • Depth is the thing being bought. Constant-depth transformers are confined to AC0\mathrm{AC}^0. Chain-of-thought buys serial depth in token space; recurrent depth buys the same thing in latent space. Two implementations of one complexity-theoretic fix.
  • Three parts, not one. A prelude P, a recurrent core R applied r times, a coda C. Huginn is (2, 4, 2) — eight real layers that unfold to 132 at r = 32.
  • Two details every summary drops: the embedded input is re-injected on every iteration, and the initial state is random, not the embedding. Together they produce path independence, which is the entire licence to change r at inference.
  • The dial is made during training, not discovered at inference: r is sampled per step from a heavy-tailed log-normal Poisson with mean 32, and the backward pass is truncated to the last k = 8 iterations, so memory depends on k and not on r.
  • Nothing about the loop is free. Storage is saved; FLOPs, wall-clock and KV cache are not. At r = 32 the KV cache is 10.6 GiB for one 4096-token sequence, against 7 GB of weights.
  • The exchange rate is measured and sublinear: φ=0.46\varphi = 0.46. One recurrence is worth r0.46r^{0.46} in equivalent unique parameters.
  • The strange result: looping buys reasoning, not knowledge — 282% of the gap recovered on math word problems against 37% on closed-book QA, confirmed independently by three groups.
  • The frontier is a router, not a loop count. Mixture-of-Recursions beats a 315M vanilla model with 167M parameters at equal FLOPs by giving each token its own depth.
  • Verdict: a genuine third scaling axis, and a component rather than a paradigm. On monitorability, the deflationary camp is right about the mechanism and the alarmed camp is right about the economics.

1. What is actually different, in four pictures

No notation in this section. Just what changes, why it helps, and what it costs. Every symbol in the post is collected in an appendix at the end.

The difference: the same layers, used again

A model is a stack of layers. Your question goes in the bottom, passes up through each layer in turn, and an answer comes out the top. Each layer is a separate pile of numbers — the "weights" — sitting in a file on disk.

An ordinary model has, say, eight layers and uses each one exactly once. A looped model has four layers and runs through those same four repeatedly. Watch which one finishes first.

An ordinary modelEight different layers. Each used once.the answer comes out hereyour question goes in here8layersdone —now idleA looped modelFour layers. Used again and again.Each climb hands its rough working down tothe next climb. Your question is fed in againalongside it, so the next pass has both.What loops is the working, not the question.the answer comes out after the last passrough working4 layersyour question, every passstores 8 layers · takes 8 passesStorage and thinking are one number.stores 4 layers · takes as many as you askHalf the storage. You choose the thinking.

That is the trick. Storage and thinking used to be the same number. Looping separates them into two dials.

Two honest notes before going on. The looped stack takes longer, not less time — you can see it still working after the other has stopped, and that is the correct picture: four passes over four layers is sixteen layers of work, and you wait for all sixteen. And this is not a free win. Four layers run four times are not as good as sixteen real layers — shared layers are worth measurably less than purpose-built ones, and section 6 puts a number on exactly how much less. What you get is most of the benefit from a quarter of the file.

(Real looped models keep a layer or two outside the loop at each end. Section 3 has the exact shape.)

What actually loops

The obvious objection: if you run the same four layers on the same question again, why doesn't it just produce the same answer again?

Because the second pass does not start over. It starts from where the first pass got to. The model carries a scratchpad of partial work — that chip in the diagram above — and each pass reads the previous pass's working, plus your original question, and improves on it. It is closer to re-reading a difficult paragraph than to asking the same question twice.

The model's rough working, filling inEach pass reads what the last one left behind, and adds to it.pass 1mostly guesswork so farpass 2the shape of an answerpass 3most of it worked outpass 4settled — more passes change littleNothing is written down where you could read it. This happens inside the model,between one word of the answer and the next. That is the part that makes somepeople nervous, and section 10 is about that argument.

Why this is a cheaper way to scale

Until now there were two ways to make a model smarter, and both are expensive.

Make it bigger. More layers, more weights, a bigger file. That costs memory on every machine that ever runs it, forever.

Make it write out its reasoning. This is what "thinking" models do — they work through the problem in words before answering. That is not a trick; it is the model buying itself more steps, out loud. But the words fill up the space available for your actual document, and you pay for every one of them.

Looping buys the same extra steps silently. It adds no weights and writes nothing down.

The dial you turn when you ask the questionSame model, same file on disk. Only the number of passes changes.12481632passesfile sizeyou payyou getthe file on disk never moveswhat you pay keeps climbingwhat you get flattens outhigher is more ·shape only, notmeasured valuesEarly on the amber line runs ahead — you get more than you pay for. By the right-hand end the indigo has overtaken it. That crossing is the point of diminishing returns.

Watch the flat green line: the file never gets bigger. That is the claim in one image — you buy more thinking without buying a bigger model. And that is worth real money: a small file that reasons like a big one fits on cheaper hardware, or fits more copies on the same machine. You convert a cost you pay always into a cost you pay only on the questions that need it.

Three things that image does not show, and you should not leave without them.

It is not free memory. The weights stay the same size, but while the model is answering it keeps a working scratchpad of everything each pass computed, and that scratchpad grows with every pass. At the highest settings it is larger than the model itself. Section 6 has the arithmetic.

The dial has to be built in. You cannot take an ordinary model and ask it to run its layers twice. It has to be trained from the start to accept any number of passes, and section 5 is about how that is done.

The returns flatten sooner than you would like. Watch the amber line go flat. For the best-documented model, more looping stops helping somewhere between eight and thirty-two passes depending on the question — and that is a lightly trained model. The one team that trained a looped model really hard found the useful range collapsed to two passes. The better the model is to begin with, the fewer extra passes it has any use for. That is the strongest argument against the whole idea and section 9 takes it seriously.

The catch: it thinks better, it does not know more

This is the part that surprised researchers, and three separate teams have now found it independently.

Extra passes help enormously with problems you have to work through — arithmetic, multi-step logic, following a chain of reasoning. They help far less with problems that just require knowing a fact. Some, but nothing like as much.

What the extra passes actually buyMeasured against what building a genuinely deeper model buys you — the dashed line.a genuinely deeper model (100%)working things outmaths word problems282%knowing facts"what year did X happen?"37%Looping beat a genuinely deeper model at reasoning, and recovered barely a thirdof the same gap at recall. Both bars are to the same scale. Section 8 has the sources.

Extra passes let a model think harder about what it already knows. They do not teach it anything new. For that you still need a bigger model.

So the practical summary, before any machinery: a looped model gets you much of the reasoning of a far larger model out of a far smaller file, by spending time rather than by getting bigger — and it is worth doing exactly when your problem needs working out rather than looking up.

A looped model is not a smaller model. It is a model that thinks longer instead of being bigger.

Everything below is how that is built and what it costs. If you only wanted the idea, you have it.


2. A fixed-depth transformer has a shape of thought it cannot have

Start with why anyone wants depth, because that is what the whole architecture is answering.

A transformer with a fixed number of layers is a parallel object. Every token's computation runs through the same bounded chain of operations, and that chain does not get longer when the problem gets harder. Li, Liu, Zhou and Ma made this precise at ICLR 2024: constant-depth, constant-precision transformers are confined to AC0\mathrm{AC}^0, a proper subset of TC0\mathrm{TC}^0. Both names denote what a circuit of fixed depth can compute: AC0\mathrm{AC}^0 allows unlimited AND and OR gates, TC0\mathrm{TC}^0 adds majority gates and is strictly larger. That is a small class. It does not contain the kinds of problems that are inherently serial — composing a permutation group step by step, iterated squaring, evaluating a circuit whose gates depend on earlier gates.

The same paper gives the escape hatch, and it is why chain-of-thought works at all. Let the model emit T intermediate tokens and read them back, and with O(log n) embedding width it can solve anything computable by a boolean circuit of size T. Chain-of-thought is not a prompting trick that happens to help. It is a depth mechanism — the context window used as a tape, every emitted token one more step of serial computation. Merrill and Sabharwal supply the other half: transformers of depth Θ(log n) express regular-language recognition (state tracking) and graph connectivity (multi-step reasoning), neither of which fixed-depth transformers can express under standard complexity conjectures.

So there are exactly two ways to buy serial depth. Spend tokens, and the computation happens in the context window where you can read it. Spend iterations, and it happens in the hidden state where you cannot.

Two ways to buy serial depthSame complexity-theoretic fix. Different currency — and only one of them is written down.Chain of thought · token spacet1t2t3t4t5each emitted token is one more step of serial computationthe context window is being used as a tapelegiblecosts: context window, latency, output tokensT steps ≈ circuits of size TLi, Liu, Zhou & Ma · ICLR 2024 · arXiv 2402.12875Recurrent depth · latent spacet1s4 = R(e, s3)s3 = R(e, s2)s2 = R(e, s1)s1 = R(e, s0)× rone weight setthe same computation, inside the hidden state, between tokensnot legiblecosts: FLOPs, wall-clock, KV cacheno context cost · no CoT data neededGeiping et al. · arXiv 2502.05171

Recurrent depth takes the second route, and everything downstream — the parameter savings, the KV cache problem, the monitorability argument — falls out of that one choice.

Chain-of-thought buys serial depth in token space. Recurrent depth buys it in latent space. They are two implementations of the same complexity-theoretic fix.

One caveat to carry through the rest of this. The complexity results above are asymptotic — they need depth that grows with the input. A looped model run at a fixed loop count r is still a constant-depth transformer, exactly as expressive as the unrolled l_P + r·l_R + l_C-layer network it is equivalent to. Looping does not change the complexity class unless you let r scale with problem size. What it changes is the price of depth, and — at inference — who gets to choose it.


3. The forward pass, precisely

Almost every explainer stops at "it runs the same layers twice." That is true and it is not enough to implement anything.

The most detailed public architecture is Huginn — a 3.5B recurrent-depth model trained on 795B tokens on Oak Ridge's Frontier — and it has three parts, not one. A prelude P embeds tokens into latent space. A recurrent core R is applied r times, reusing one weight set. A coda C decodes the final latent state into logits. The paper writes the shape as a triplet (l_P, l_R, l_C); Huginn is (2, 4, 2). Eight real layers.

# Standard decoder-only transformer — L weight sets, one position
x = Embed(t)
for l in range(1, L + 1):
    x = Layer_l(x)          # each layer used exactly once
p = Unembed(Norm(x))
# depth L is a property of the checkpoint. Nothing picks it at call time.

# Recurrent depth — 3 weight sets, one position
e = P(t)                    # prelude, l_P layers
s = trunc_normal(0, 2/5)    # s is RANDOM, not e
for i in range(1, r + 1):   # r is an ARGUMENT
    s = R(e, s)             # core, l_R layers, ONE weight set
p = C(s)                    # coda, l_C layers
# depth = l_P + r*l_R + l_C

Two details in that second block are where the architecture actually lives, and both are routinely dropped in summaries.

The embedded input is re-injected at every iteration. The core does not take s alone; it takes R(e, s_{i−1}), and internally an adapter matrix A: ℝ^2h → ℝ^h projects the concatenation [s_{i−1} ; e] back down to the hidden dimension before the four transformer layers run. Why that is load-bearing rather than incidental is checked numerically below.

The initial state is random. s_0 is drawn from a truncated normal with variance σ_s² = 2/5, cut at 3σ — fresh, per forward pass. Not from the embedded input, which is the obvious choice and the wrong one. Random initialisation together with input injection is what produces path independence (Anil et al., 2022): different initialisations converge to the same trajectory. That property is not cosmetic. It is the thing that makes it legitimate to change r at inference at all — without it, a loop count the model was never trained at is just an out-of-distribution query.

One forward pass, unrolledHuginn · (l_P, l_R, l_C) = (2, 4, 2), shown at r = 4p — next-token logitsC · coda2 layers · own weightss4i = 4s4 = R(e, s3)s3i = 3s3 = R(e, s2)s2i = 2s2 = R(e, s1)s1i = 1s1 = R(e, s0)s0 ~ Normal(0, 2/5 · I), truncated at3 sigma — random, drawn fresh, andnot the embedded inputP · prelude2 layers · own weightsinput tokense = P(t)re-injected atevery iteration× rone weight set,applied r timesr is chosenat inferenceeffective depth2 + 4r + 2= 132 at r = 32

The bus on the left is the detail most summaries lose: the embedded input e enters the core on every pass, not once at the bottom. The prelude and coda are ordinary transformer layers with their own weights, used exactly once — only the core is shared, and only the core's cost scales with r.

Inside the core block:

# adapter: concatenate the state with the input, project back down to h
A : R^(2h) -> R^h
R(e, s) = Block^(l_R) ( A([ s ; e ]) )

# each layer uses "sandwich" RMSNorm (n1..n4) — load-bearing at scale
x_hat = n2( x     + Attn( n1(x)     ) )
x     = n4( x_hat + MLP ( n3(x_hat) ) )

Attention is standard causal self-attention with RoPE (base 50000) and a gated SiLU MLP; RMSNorm ε = 1e−6; learnable biases on queries and keys and nowhere else. Ordinary, in other words.

Inside one application of the coreShapes for a 10-token prompt at h = 5280. This is what R(e, s) expands to.s_i−1[10, 5280]e[10, 5280]concatenate[10, 10560]A · adapter10560 → 5280, 55.8M weights[10, 5280]4 × sandwich blockl_R = 4, run in sequence[10, 5280]s_i — [10, 5280], same shape as s_i−1one sandwich block, expandedNormalisation before and after each sub-layer —the "sandwich". Ordinary pre-norm was one of thetwo configurations whose training runs collapsed.x̂ = n2( x + Attn( n1(x) ) )x = n4( x̂ + MLP ( n3(x̂) ) )n1…n4 are RMSNorm · Attn is causal, with RoPEWhy the shape never changesThe block maps [10, 5280] to [10, 5280]. That is whatmakes reapplying it type-correct — and it is the onlystructural requirement the loop imposes.The adapter exists to absorb the extra 5280 numbersthat re-injecting e brings in.

Following one 10-token prompt all the way through makes the shapes concrete. Nothing here is batched, h = 5280, and r = 32:

StepWhat happensShape after itRun how often
ttokenised prompt[10] integers—
e = P(t)prelude embeds and runs 2 layers[10, 5280]once
s_0random draw, trunc-normal σ = 0.632[10, 5280]once per forward pass
[s_{i−1} ; e]concatenate state and input[10, 10560]32×
A([s_{i−1} ; e])adapter projects back down[10, 5280]32×
4 core layersattention + MLP, four times[10, 5280]32× (= 128 layer applications)
s_32the final state[10, 5280]—
C(s_32)coda, 2 layers[10, 5280]once
unembedproject to vocabulary[10, 65536]once

The only tensor that grows is the concatenation, and the adapter immediately undoes it. Everything else in the loop is shape-preserving, which is the structural reason the block can be reapplied at all.

The third detail is a negative result worth more than most positive ones: the core block takes no step index. The authors tried the obvious variant — a step-conditioned core s_i = R_i(e, s_{i−1}) with a diffusion-style timestep embedding, so that iteration seven knows it is iteration seven — and report it "interacts badly with path independence, leading to models that cannot extrapolate." The block has to be blind to which iteration it is on. Whatever it has learned is therefore not a 32-step program; it is one step of something applicable an unspecified number of times.

Checking the two details numerically

Both claims above — that re-injecting e matters, and that random s_0 is safe — are testable in about twenty lines, with no model. Take a random contraction in place of the four learned layers and iterate it:

import numpy as np
np.random.seed(0)
h = 8
A = np.random.randn(h, 2 * h) / np.sqrt(2 * h)   # adapter, 2h -> h
W = np.random.randn(h, h) / np.sqrt(h)           # stands in for the core's 4 layers
e = np.random.randn(h)                            # the embedded input, held fixed

def core(s, e):                                   # R(e, s), with input injection
    return np.tanh(W @ (A @ np.concatenate([s, e])))

states = [np.random.randn(h) * 0.632 for _ in range(4)]   # four different s_0
for i in range(1, 25):
    states = [core(s, e) for s in states]
    if i in (1, 4, 8, 16, 24):
        spread = max(np.linalg.norm(a - b) for a in states for b in states)
        print(f"after {i:2d} iters, max distance between trajectories = {spread:.2e}")
after  1 iters, max distance between trajectories = 1.05e+00
after  4 iters, max distance between trajectories = 8.90e-02
after  8 iters, max distance between trajectories = 1.85e-03
after 16 iters, max distance between trajectories = 1.18e-06
after 24 iters, max distance between trajectories = 8.23e-10

Four different random starting states, four trajectories, one destination. That is path independence, and it is why s_0 can be noise: after enough iterations the state depends on the input and the weights, not on where it started. It is also why changing r at inference is legal rather than an out-of-distribution query — the model is not executing a 32-step program that breaks when you ask for 40.

The second half of the experiment is the more interesting one. Run the same core on two different inputs e and e2, and the two fixed points sit a distance of 1.116 apart — the input determines where the iteration lands, which is the entire point of running it. Now delete the injection, so that e enters only through s_0, and repeat:

def core_noinj(s):                                # e enters only via s_0
    return np.tanh(W @ (A @ np.concatenate([s, np.zeros(h)])))
distance between the fixed point reached from e and from e2 = 1.80e-04

Four orders of magnitude smaller. The same property that made the loop safe — forgetting where it started — has now made it useless, because the input is where it started. The deep state converges to a place determined by the weights alone, and the prompt has been washed out.

Why the input is re-injected every iterationSame 20-line experiment, run both ways. Distances are the measured output.with input injectionfixed point for e4 random starts → 8.2e-10 apartfor e21.116random s_0the input decides where you landwithout input injectionstart = estart = e2one point1.8e-4 apartthe prompt is washed out by depth

The paper's own justification is an analogy to gradient descent — you cannot optimise a data-dependent objective by looking at the data once — and the experiment above is that sentence made checkable. Formally, if e entered only through s_0, the core could not be a monotone operator on data-dependent functions: its fixed point would be a property of the weights alone rather than of the input.

Huginn-0125ValueWhy it matters
Shape (l_P, l_R, l_C)(2, 4, 2)Eight real layers. At r = 32 it unfolds to 2 + 4r + 2 = 132.
Hidden size h528055 heads × 96. No grouped-query attention — which is why the KV numbers later are what they are.
MLP inner / vocab17920 / 65536Otherwise an entirely ordinary transformer layer.
Parameters1.5B prelude+head, 1.5B core, 0.5B embeddingOnly the middle 1.5B is re-run. The rest is paid once, whatever r is.
Initial state s_0trunc-normal, σ² = 2/5, cut at 3σRandom per forward pass. Enables path independence.
Init schemeσ_h² = 2/5h, σ_out² = 1/5hl, l = 132Out-projections are scaled by the unrolled depth, not the real one.
Context4096Latent reasoning does not consume context. This is the point.
Training run795B tokens, 4096 × MI250XFrontier, 16M tokens/step, 52–64 TFLOP/s per GPU (41–51% AFU).

4. What actually changes, line by line

"It loops" is not a difference an engineer can plan around. These are.

PropertyStandard transformer, L layersRecurrent depth, (l_P, l_R, l_C) × r
Distinct weight setsL blocks, each used oncel_P + l_R + l_C blocks. Only the core is reused.
Effective depthL — a property of the checkpointl_P + r·l_R + l_C — an argument at call time
Non-embedding parametersLinear in LIndependent of r. Adding depth adds no weights. This is the whole selling point.
Forward FLOPs / token≈ 2N≈ 2(N_once + r·N_rec) — linear in r. Depth is not free; it is just not paid in storage.
Weight bytes read per token, batch-1 decode≈ N≈ N_once + r·N_rec — identical to the dense model of the same effective depth. Storage is saved. Bandwidth is not, unless the core stays resident in on-chip cache.
KV cacheL layers × context(l_P + r·l_R + l_C) layers × context. Every iteration writes its own entries. Grows linearly with r unless you share.
Peak activation memory, trainingO(L)O(l_P + k·l_R + l_C) with truncated backprop — independent of r. Huginn fixes k = 8.
BackpropagationThrough all L layersThrough the last k iterations only. The prelude still gets gradient on every step, because e is injected on every step.
Decode latency / tokenOne passr serial core passes. The iterations are a dependency chain and cannot be parallelised away.
Parallelism needed to trainTensor / pipeline parallel as N growsHigh FLOPs per parameter, so data parallel plus ZeRO-1 suffices. Huginn trained on 4096 GPUs with a hand-written DDP routine and no model parallelism.
Fixed at training timeEverythingBlock shapes, and the distribution r is sampled from — not r itself.
Choosable at inferenceNothing about depthr, per request — and, with an exit rule, per token.
Knowledge capacityScales with parametersScales with parameters. Unchanged by r.

A looped model is not a smaller model. It is a model whose depth has been moved out of the weight file and into the call signature.


5. You do not train it at a depth. You train it over a distribution of depths.

This is the least-covered part of the architecture and the most interesting, because it is where the test-time dial is actually manufactured.

If you trained at a fixed r, you would get a model that works at that r and degrades away from it — which is just a deep model with tied weights. Instead the loss is an expectation over sampled depths:

L(θ)  =  Ex Er∼Λ  L(mθ(x,r), x′)\mathcal{L}(\theta) \;=\; \mathbb{E}_{x}\,\mathbb{E}_{r \sim \Lambda}\; L\big(m_\theta(x, r),\, x'\big)

Every optimiser step draws a new r from a log-normal Poisson distribution Λ with mean 32 and σ = 1/2:

τ∼N ⁣(log⁡rˉ−σ22,  σ),r∼Poisson ⁣(eτ)+1\tau \sim \mathcal{N}\!\left(\log \bar r - \tfrac{\sigma^2}{2},\; \sigma\right), \qquad r \sim \mathrm{Poisson}\!\left(e^{\tau}\right) + 1

The distribution is deliberately heavy-tailed: most steps run shallower than 32, and occasionally one runs far deeper. Which raises the obvious objection — if some steps unroll to 60 or 80 iterations, the activation memory should be catastrophic. It is not, because the backward pass is truncated: gradients flow through the last k = 8 iterations only. Memory and backward compute are therefore functions of k, not of r, and the heavy tail becomes affordable. Textbook truncated backpropagation through time, applied to depth instead of to time.

Training: depth is sampled, gradients are truncatedOne optimiser step. r is drawn fresh; the backward pass sees only the last k.1 — sample rmean r = 321326490r_bar = 32, sigma = 1/2one r per micro-batch, synchronisedacross all 4096 workers — "locked-stepsampling", so no worker idles waitingfor a deeper peertau ~ Normal( log r_bar - sigma^2/2 , sigma )r ~ Poisson( e^tau ) + 1the heavy tail is the point: occasional very deep unrolls2 — unroll r times, backprop through the last k = 8forward only · activations discardedbackward pass · k = 8i = 1i = rPe is injected at every i — so the prelude receives gradient on every step3 — consequencePeak activation memory and backward FLOPs depend on k, not on r.

Depth extrapolation is manufactured here, not discovered at inference. Because the model has never been told which iteration it is on, and because it has seen many different r values with gradient only ever arriving through the last eight, the core learns an operator that is safe to apply an unspecified number of times.

Three consequences follow, and the third is the interesting one.

Stability is not automatic. The paper is unusually honest about this: two large runs failed before the third worked. A version with parameter-free RMSNorm, a parameter-free additive adapter A(s, e) = s + e and a peak learning rate of 4e−4 stalled with hidden-state collapse; a second collapsed the recurrence itself, with token correlation driving toward 1.0 — the model learning to ignore its own loop. The fix was the sandwich normalisation, a learned adapter, and dropping the peak learning rate by a factor of ten to 4e−5. At small scale every normalisation scheme worked. At scale, only one did.

Backprop is shorter than the forward pass, and that is fine. A model can be trained through 8 iterations and run at 32 or 64. The gradient never saw the deep regime. That should be alarming and mostly is not, because of the step-blindness above: what the core is being taught is not a 32-step program but a single step of a convergent operator.

Depth extrapolation at test time is the surprising part. The model was trained with a single r per sequence, and yet at inference different tokens converge at different rates — the authors show latent states settling quickly on filler and slowly on the semantically loaded words of a question. Nobody trained that. Nor is the convergence uniform in kind: PCA of the latent trajectories shows fixed points on most tokens, multi-dimensional orbits on arithmetic, and steady directional drift — "sliders" — that would let the model count how many iterations it has taken.

How far the extrapolation actually goes, stated honestly. The paper evaluates 1 to 64 iterations and plots convergence out to 128. It does not demonstrate unbounded depth. Saturation is task- and context-dependent: roughly 8–12 iterations zero-shot, about 20 with one in-context example, about 32 with 25–50 — the model uses more depth when there is more context to reason over. "Improves with more compute" is supported; "improves without limit" is not claimed.


6. Looping trades storage for time. It does not create compute.

The single most common error in the coverage of this architecture was treating the loop as free because it adds no weights. Here is the arithmetic for Huginn at each loop count, from its published parameter split.

rEffective layersForward GFLOP / tokenDense model with the same FLOPsKV cache / token, naïveKV / token, cache budget 4Serial passes / token
186.03.0B165 KiB165 KiB1
42015.07.5B412 KiB412 KiB4
83627.013.5B743 KiB412 KiB8
166851.025.5B1.37 MiB412 KiB16
3213299.049.5B2.66 MiB412 KiB32
64260195.097.5B5.24 MiB412 KiB64

Assumptions, so you can check this. Forward FLOPs taken as 2·(N_once + r·N_rec) with the paper's split N_once = 1.5B and N_rec = 1.5B. The factor of 2 is the standard accounting rule: every weight participates in one multiply and one add per token, so a forward pass over N parameters costs about 2N floating-point operations — and here the core's parameters are traversed r times rather than once. KV cache taken as (l_P + r·l_R + l_C) × 2 × h × 2 bytes in bf16 at h = 5280 with full multi-head attention — Huginn has no grouped-query attention. The "cache budget 4" column applies the paper's own zero-shot sharing scheme, which writes to cache slot i mod k. The r = 32 row lands on 49.5B, which is the derivation behind the paper's own statement that the model reaches "FLOP budgets equivalent to a standard 50B parameter fixed-depth transformer." Those parameter figures are compute equivalences, not claims of parity with a 50B model — and the two get conflated constantly.

Three things in that table deserve to be said out loud.

The KV cache is the sleeper problem. Every iteration runs real attention and writes its own keys and values, so the cache scales with effective depth, not with real layers. At r = 32 and a 4096-token context that is 10.6 GiB of cache for a single sequence — for a model whose weights are 7 GB in bf16. That is why the paper has a section on cache sharing at all, and the mitigation is not free either: Nanbeige tested sharing the KV cache across loop passes, found it "reduces the KV-cache by half" and that "its performance gains are consistently lower than those of the full, non-sharing loop configuration," and shipped the expensive version anyway.

The KV cache is the sleeper problemCache per token, bf16, no grouped-query attention. It scales with effective depth, not with real layers.r = 1165 KiBr = 4412 KiBr = 8743 KiBr = 161.37 MiBr = 322.66 MiBr = 645.24 MiBthe dashed line is the paper's cache sharing: flat at 412 KiB for any r— and Nanbeige measured the quality cost, then declined itAt r = 32, one 4096-token sequence10.6 GiB of cachefor a model whose weights are 7 GB.Per token, per layer: 2 tensors × 5280 × 2 bytes= 20.6 KiB, × (2 + 4r + 2) layers.Grouped-query attention would divide this — Huginnhas none: all 55 heads keep their own keys and values.This number decides whether the architecture is deployableat long context, and it is the one least often quoted.

In practice, what r should you set? The paper's own saturation points make a usable rule, and they are not constant — the model spends more depth productively when there is more context to reason over:

SituationWhere returns flattenReading
Zero-shot questionr ≈ 8–12Little to integrate; the state settles early.
One in-context exampler ≈ 20More to reconcile, more depth used.
25–50 in-context examplesr ≈ 32The trained mean, and roughly where it stops paying.
Beyond thatevaluated to 64, plotted to 128Improvement is not demonstrated to continue.

Nobody trained those thresholds. They are where a model trained across a distribution of depths happens to stop changing its mind.

Storage is saved; bandwidth is not. At batch-1 decode you still stream the core weights r times through the memory system.

Storage is saved. Bandwidth is not.Huginn at r = 32, batch-1 decode. Bars to scale, 12 px per billion parameters.weight footprint — what you have to store3.5B parameters · about 7 GB in bf16weight traffic per token at r = 32 — what you have to move49.5B-equivalentThe core's 1.5B is streamed through the memory system r times. Only a core small enough to stay resident in on-chipcache escapes this — the edge regime, not the frontier one. Meanwhile the KV cache is 10.6 GiB for one sequence.

elie bakouch, who builds these, put it in a line: "Why recurrent depth instead of just scaling depth? It's not faster at inference or training… since you still go through the full 'effective depth'. The advantage is storage."

The exchange rate is sublinear, and it has been measured. Schwethelm, Rueckert and Kaissis ran an iso-depth pretraining sweep over r ∈ {1, 2, 4, 8} across roughly 50× in training compute and fitted a joint scaling law in which recurrence enters as a power of r multiplying the recurrent parameter count:

L  =  E  +  A(Nonce+rφNrec)−α  +  B D−β,φ=0.46\mathcal{L} \;=\; E \;+\; A\big(N_{\text{once}} + r^{\varphi} N_{\text{rec}}\big)^{-\alpha} \;+\; B\,D^{-\beta}, \qquad \varphi = 0.46
What one recurrence is actually worthEquivalent unique parameters bought by the recurrent block, log–log. Both axes double per tick.11×22×44×88×1616×3232×6464×loop count rslope 1 — what a real layer givesr^0.46 — measuredφ = 0.46Fitted over r ∈ 1, 2, 4, 8 acrossroughly 50× in training compute.At r = 4, a 410M looped modelmatches a 580M unlooped one —on the compute of a 1B one.Schwethelm, Rueckert & KaissisarXiv 2604.21106

One recurrence is worth r0.46r^{0.46} in equivalent unique parameters — genuinely positive, and considerably less than one. That exponent is the honest centre of the subject. It is the reason a looped 3B behaves like something bigger, and the reason it does not behave like something much bigger.

Two practitioner quotes worth keeping alongside it. Sebastian Raschka, on a two-pass looped model: "almost 2× as expensive in terms of compute, because we run the embedded text through almost 2× as many layers." And the Nanbeige team, who actually shipped one, on what a second pass buys: "relative to a standard Transformer, it retains approximately 75% of the token efficiency and provides a significant capacity gain." A looped layer is not a real layer, and somebody measured by how much.

Set against the three ways a model can be given more compute, the trade becomes legible:

Scaling axisWhat it buysWhat it costsIn the transcript?
More parametersKnowledge capacity and reasoning, jointlyWeight storage, HBM footprint, memory bandwidth, interconnect, training computen/a
More output tokens (chain-of-thought)Serial depth in token space. T steps ≈ circuits of size T.Context window, latency, per-token billing. Needs long-CoT data or RL to elicit.Yes — it is the transcript
More latent iterations (recurrent depth)Serial depth in latent space, at flat parameter countFLOPs, wall-clock, KV cache. No context cost, no specialised data.No

7. The interesting version is not a fixed loop count

A fixed r is a blunt instrument: the token the gets the same 32 passes as the operative word in a hard question. Every serious line of work in this area is converging on the same next move — let the model decide the depth per token — and there are now three distinct ways to do it.

Emergent, zero-shot. Huginn exits when the KL divergence between two successive latent states falls below 5e−4. Nothing was trained for this; the criterion is applied after the fact to a model that happened to converge. It works: on MTBench — a standard multi-turn chat benchmark graded out of 10 — the model scores 5.63 running every iteration and 5.56 exiting early, for a large saving in compute. And the exit distribution is semantically sensible — the model leaves early on high-school mathematics and takes about 3.5 steps longer on moral scenarios.

Learned halting. The Universal Transformer had this in 2018, with per-position Adaptive Computation Time. Ouro, ByteDance's 2025 looped family, trains an entropy-regularised objective for learned depth allocation directly in pretraining.

Learned routing. Mixture-of-Recursions goes further: a lightweight router assigns each token its own recursion depth, and the KV cache is restructured to match. Two routing schemes, with a genuine trade-off. Expert-choice has each depth select its own top-k tokens, which gives perfect load balance by construction but leaks information across the causal boundary during training — fixed with an auxiliary loss that teaches the model to detect the top-k threshold at inference. Token-choice commits each token to a depth up front, which is causally clean but needs a balancing loss to stop every token stampeding to the same depth. Of four weight-sharing layouts, Middle-Cycle — unique first and last layers, shared middle — consistently wins.

Fixed loop count vs. learned per-token depthMixture-of-Recursions: a router assigns each token its own recursion depthFixed r = 4every token pays the sameeight tokens →depth 432 passesKV written at all 4 depths,for every tokenRouted depththe router picks a depth per tokenlearned router21 passesKV written only at the depthsa token actually reaches

Dashed cells are passes the router declined to spend. The consequence is not only cheaper compute: under recursion-wise caching, only the tokens routed to depth d write KV entries at depth d, which brings cache memory down to (N_r + 1)/2N_r of a vanilla model's. The alternative — recursive sharing, cache once at step 1 and reuse everywhere — reaches 1/N_r but pays it back in attention FLOPs.

The numbers are the strongest efficiency result in the field. At an equal training budget of 16.5e18 FLOPs, a 167M-parameter MoR model reaches 43.1% few-shot average against a 315M vanilla transformer's 42.3% — better, with 47% fewer parameters. It trains 19% faster, peaks 25% lower on memory, and reaches up to 2.06× inference throughput through "continuous depth-wise batching," which works precisely because tokens at different recursion depths can be packed into one batch. That last figure comes from the depth-4 configuration, which the authors note degrades slightly in quality — a throughput-for-accuracy trade, not a free lunch. (It also circulates as 2.18× rather more often than it should.)

Be precise about what changes here, because it is a different thing from looping itself. With a fixed r, compute per token is a deployment constant: you set it, you can log it, you can bill for it. With a learned router, how much thinking each token receives becomes a hidden, input-dependent decision inside the model. For capability that is the entire point. For anyone trying to observe the system from outside, the change is not that the reasoning became unreadable — it is that the amount of reasoning became an unlogged variable.


8. What the literature actually establishes

Strip away the Astra story and there is a real, unusually clean research result underneath, now confirmed by three groups using different methods at different scales: looping buys reasoning, not knowledge.

The headline numbers below use a metric — "% of the gap recovered" — that is worth unpacking, because 282% sounds like a typo and is not.

Reading the "% of gap recovered" metricTwo baselines pin the scale. The looped model is scored between them — and can overshoot.0%iso-parameter baselinesame weights, no loop100%iso-FLOP baselinea genuinely deeper model, same compute"the gap" — what real depth buys37%closed-book QA282%math word problemsOver 100% means the looped model beat the deeper model it was being measured against — on reasoning.On recall it recovered barely a third of the same gap.
Loops buy thinking, not factsShare of the iso-parameter-to-iso-FLOP gap that looping recovers · Saunshi et al., ICLR 2025math word problems282%closed-book QA37%Virtual Logic Depth — weight reuse "substantially improves reasoning ability without more parameters" whileleaving "knowledge capacity nearly unchanged", across architectures and reuse schedules.Ouro (ByteDance, 7.7T tokens) — the advantage "stems not from increased knowledge capacity, but fromsuperior knowledge manipulation capabilities."
ResultFindingScale
Latent thoughts — Saunshi, Dikkala, Li, Kumar, Reddi · ICLR 2025 · arXiv 2502.17416A 1-layer block looped 12 times reaches 99.9 on 8-operand addition, matching a real 12-layer model; on the i-GSM math benchmark a 1-layer block looped 8 times scores 73.2, matching the real 8-layer model, against 24.5 for a single unlooped layer. Theorem 5.4 constructs, for any L-layer model, a looped transformer whose output after m loops equals the original's after m steps of chain-of-thought. Their "% gap" metric is 282% on math word problems and 37% on closed-book QA.synthetic + 1B LM
Huginn-0125 — Geiping, McLeish, Jain, Kirchenbauer et al. · arXiv 2502.05171The first recurrent-depth model trained at scale, and the only fully specified one. Performance improves with test-time iterations up to a FLOP budget equivalent to a 50B dense model. No specialised CoT data, 4096-token context. Per-token adaptive exit emerges zero-shot.3.5B params, 795B tokens, r ∈ 1…64
Virtual logic depth — Zhu, Zhang, Li, Shi et al. · arXiv 2506.18233The cleanest decoupling result. Weight reuse "substantially improves reasoning ability without more parameters," while at constant parameter count it "leaves knowledge capacity nearly unchanged" — and capacity still scales with parameters across models. Robust across architectures and reuse schedules.multi-arch sweep
Ouro / LoopLM — Zhu, Wang, Hua et al. (ByteDance) · arXiv 2510.25741Independent confirmation, at production scale and by a different route: 4 recurrent steps, entropy-regularised learned depth allocation. Ouro-1.4B matches Qwen3-Base-4B (BBH 71.02 vs 70.95; GSM8K 78.92 vs 72.86); 1.4B and 2.6B match models up to 12B.1.4B / 2.6B, 7.7T tokens
Mixture-of-Recursions — Bae et al. · NeurIPS 2025 · arXiv 2507.10524Per-token learned recursion depth plus recursion-aware KV caching. At equal FLOPs, 43.1% few-shot average on 167M parameters against a 315M vanilla model's 42.3%; 19% less training time, 25% lower peak memory, up to 2.06× throughput.135M – 1.7B
Iso-depth scaling law — Schwethelm, Rueckert, Kaissis · arXiv 2604.21106Prices the loop. Fitting loss = E + A(N_once + r^φ·N_rec)^−α + B·D^−β over r ∈ {1,2,4,8} gives φ = 0.46. Depth-by-looping is real and sublinear in the loop count.~50× compute span
LOTUS — Fan, Svete, Lee · arXiv 2606.31779The honest counterweight. Latent chain-of-thought had been losing to explicit chain-of-thought above 1B parameters, with the gap widening as models grew. A looped padded backbone with cross-entropy supervision on each latent position closes it at 3B and cuts thought-phase latency 2.5–6.9×. Note the cost: it needs gold CoT steps to supervise against — reintroducing exactly the data requirement recurrent depth was supposed to remove.3B params
Nanbeige 4.2-3B — arXiv 2607.22083 · open weightsA shipped looped model, trained from scratch rather than upcycled — which the authors found "performs significantly better." 22 layers run twice. Reported to outperform Qwen3.5-9B and Gemma4-12B on agentic benchmarks at roughly a quarter of the parameters.3B params, 28T tokens
MoEUT — Csordás, Irie, Schmidhuber, Potts, Manning · arXiv 2405.16039The composition question, partly answered. Shared layers have a bad parameter-to-compute ratio; mixture-of-experts is the natural fix. MoEUT is the first shared-layer transformer to slightly outperform standard transformers on language modelling while using less compute and memory.up to 1B
Lattice deduction — Alfarano et al. · Axiom Math / Amherst / BarnardAn existence proof at the other end of the scale: a looped transformer that reasons like a SAT solver reaches 100% on Sudoku-Extreme after fifteen minutes of training.800K params

Loops buy thinking, not facts. If you want a model that knows more, you still need parameters. If you want one that thinks harder, you can now turn a dial — and pay for it in time rather than in memory.

I find this genuinely odd, and I do not think the field has absorbed it. Parameter scaling has always moved knowledge and reasoning together, so we never had cause to treat them as separable knobs. Recurrent depth separates them cleanly enough that three independent methodologies agree — and that result outlives the news cycle that made anyone look.


9. Is this the architecture that pushes models further?

Partly, and not in the shape the coverage implied. The evidence supports a narrow claim and does not support a broad one.

The narrow claim: recurrent depth is a genuine third scaling axis with a measured exchange rate of r0.46r^{0.46}, and it moves reasoning without moving knowledge. That is a scaling law, not a slogan, and the knowledge-versus-reasoning split has been reproduced independently — by the Virtual Logic Depth and Ouro teams, on different architectures, at different scales, with different objectives. Anyone shipping a small model should be looking at it today.

The broad claim — that this is the architectural change that takes frontier models to the next level — is not supported, and one specific piece of evidence cuts against it. Nanbeige trained at 28T tokens, an order of magnitude beyond any other published looped model, and found that going past two passes bought almost nothing while destabilising optimisation: "increasing the number of passes provides only marginal additional improvement, but substantially slows training and makes optimization less stable." At 28T tokens the sweet spot was r = 2. Huginn's own returns saturate between 8 and 32 iterations depending on how much context there is to chew on. The exchange rate is sublinear by construction. Three attempts were needed to train one 3.5B model at all. None of that is what a discontinuity looks like from the inside.

Where it clearly helps

  • Depth-bound, serial reasoning. Arithmetic, state tracking, graph connectivity, algorithmic search. The 282%-vs-37% split between math word problems and closed-book QA is the shape of the whole effect.
  • Parameter-constrained deployment. A 3B that behaves like a 12B is worth more on a laptop, a phone or a memory-bound serving tier than anywhere else. This is where the shipped models actually are.
  • Test-time compute without context growth. No CoT data, no RL to elicit it, no context consumed, and it composes with a 4K window. LOTUS cuts thought-phase latency 2.5–6.9× against writing the reasoning out.
  • Interconnect-poor training clusters. High FLOPs per parameter means data parallelism suffices. Huginn ran 4096 GPUs with no model parallelism at all.

Where it does not help

  • Anything bound by memorised facts. Two independent results say knowledge capacity is flat in r and still tracks parameters. No amount of looping makes a model know more.
  • Wall-clock latency. The iterations are a serial dependency chain. You pay the full effective depth in time. Storage is the saving; speed is not.
  • Long-context serving. KV cache grows linearly in r. The sharing fix works and measurably costs quality — Nanbeige declined it.
  • Large loop counts. Sublinear returns, saturating benchmarks, and optimisation that gets less stable the deeper you go.

What is genuinely unsolved

  • Stability at large effective depth. Huginn needed three attempts, a sandwich-norm block and a 10× learning-rate cut. Nobody has published a recipe known to hold at frontier scale.
  • Composition with sparsity. Every frontier model is a mixture-of-experts; every looped result is dense. MoEUT shows the combination can work below 1B and is arguably necessary, since shared layers have a poor parameter-to-compute ratio. Above that, nothing public.
  • Whether depth extrapolation survives scale. It is demonstrated at 3.5B on 795B tokens. The one 28T-token data point suggests the useful range of r shrinks as training gets long.
  • Post-training. Outcome-level RL still works, but the process supervision that drives current reasoning models has no purchase on a step you cannot read. LOTUS's answer — supervise latent positions against gold CoT tokens — works, and gives back the data dependency that was the point.

The likely future is not looped models replacing transformers. It is a small loop count, a learned router and a sparse MoE core, all in the same model — with recurrent depth as a component rather than a paradigm.

Which is roughly what Mixture-of-Recursions already is, at 1.7B. What is missing is everything above that scale.


10. Back to the argument, which was two arguments

Which brings us back to where this started. Both camps argued well and mostly past each other, because the question they had merged is really two questions with two different answers.

One argument, two questionsThey have different answers, which is why September went the way it did.mechanismDoes looping itself removethe chain of thought?NoThe loop is a depth mechanism, anddepth has never been legible.Extra iterations add computation between emittedtokens exactly as extra layers always have.economicsDoes cheap latent computeerode the transcript over time?YesLatent depth costs no context and nooutput tokens. Written reasoning costs both.Once thinking in activations is the cheap path, everyefficiency pressure moves reasoning off the page.

On question one, the deflationary camp is right, and everything above is one long demonstration of why. Nothing in the mechanism supports the alarming reading: extra iterations add computation between emitted tokens exactly as extra layers always have, and the model still writes its reasoning out. Pachocki's "within a factor of two of GPT-4" is a claim about effective depth, which for a looped model means a small r — the regime where, at φ=0.46\varphi = 0.46, this is a modest efficiency choice rather than a new kind of system.

On question two, the alarmed camp is pointing at something real, and it does not depend on the Astra rumour being true at all. Nobody has to decide to hide anything. The most striking thing in the whole episode is that OpenAI's chief scientist agrees the transcript is degrading; he just says the architecture is not why.

The architecture is not the threat. The gradient is. Both sides concede the same trend — they disagree only about its cause.

The consequence for anyone building on these models is unchanged by the technical detail, and possibly sharpened by it. If legible reasoning is something you depend on — for audit, for evaluation, for debugging an agent that touches production — stop treating it as a property of the architecture you happened to buy and start treating it as something you specify, price and test for. And note which direction the frontier is heading: per-token routed depth, where the amount of computation spent on a token is itself a learned and unlogged decision. That is a monitorability question with real content, and it is not the one anyone spent September arguing about.


11. What would actually settle this

  1. Does depth extrapolation survive at frontier scale? The only public demonstration is 3.5B on 795B tokens. The only 28T-token data point says the useful loop range shrinks. This is the load-bearing empirical question for the whole architecture and it is open.
  2. Does it compose with sparsity? MoEUT works below 1B. Every frontier model is a mixture-of-experts. Nobody has published a large looped-plus-sparse model, and the parameter-to-compute argument says that combination is where the real design lives.
  3. What does the KV cache actually cost in production? Naïve caching scales with effective depth; both published mitigations trade quality or FLOPs. A serving-side study at long context would settle whether this architecture is deployable where it is most wanted.
  4. Can latent steps be supervised without gold CoT? LOTUS closes the latent-versus-explicit gap by supervising each latent position against a written reasoning step. Doing it without that crutch is the difference between an efficiency trick and a new training paradigm.
  5. Astra's loop count, if any. "Within a factor of two of GPT-4" implies a small r. Publishing the number would end that argument in a sentence — and, per everything above, probably in the deflationary direction.
  6. Did reasoning tokens per task go down? The measurable version of the safety worry, testable from outside. If Astra writes visibly less reasoning than the o-series for equivalent tasks, the economics argument has teeth.

Not one of those turns on what Astra does. The rumour was never the interesting part. It was the thing that got everybody to look.


Appendix: notation and jargon, for reference

Nothing in this appendix is needed to follow the argument — it is here so that when a symbol shows up in the sections above, there is one place to look it up.

Where every symbol livesHuginn-0125. Read left to right; the loop is the middle third.ttokensPpreludel_P = 2 layersrun onceeRrecurrent cores_i = R(e, s_i−1)l_R = 4 layers · ONE weight setre-run r times× re is injected on every one of the r passess_0random · trunc-normal, variance 2/5the state runs s_0 → s_r; each s_i is 5280 numbers per tokens_rCcodal_C = 2 layersrun onceplogitseffective depthl_P + r·l_R + l_C = 2 + 4r + 2= 132 at r = 32, from 8 real layersparameters3.5B total, independent of ronly the core's 1.5B is re-run

The architecture symbols

SymbolWhat it isIn Huginn
tThe input token ids — the prompt after tokenisation.up to 4096 of them
PThe first block of ordinary transformer layers. Runs once, converts tokens into vectors the loop can work on.2 layers
eThe embedded input: what P produced, e = P(t). One vector per token. Held fixed for the whole loop and fed back in at every iteration.one 5280-vector per token
RThe recurrent core — the block that gets repeated. One set of weights, applied r times.4 layers
s_iThe latent state after i applications of the core. This is the thing being refined — the model's working scratchpad, in vectors rather than words.one 5280-vector per token
s_0The initial state, before any core pass. Drawn at random, freshly, on every forward pass.trunc-normal, variance 2/5
rThe loop count — how many times R is applied. The dial. Chosen per request at inference.trained around 32, evaluated 1–64
CThe last block of ordinary layers. Runs once, turns the final state into predictions.2 layers
pThe output logits — one score per vocabulary entry, for the next token.65,536 scores
l_P, l_R, l_CLayer counts of prelude, core and coda. Written as a triplet (l_P, l_R, l_C).(2, 4, 2)
LLayer count of an ordinary (unlooped) transformer, for comparison.—
hHidden size — the length of every one of those vectors.5280
AA learned matrix that squashes the state and the input back into one vector: A maps 2h numbers to h.10560 × 5280 ≈ 55.8M weights
kBackprop truncation depth — how many of the r iterations the gradient is allowed to flow through during training.8
Λ, r̄, σ, τThe distribution r is drawn from during training, its mean, its spread, and the intermediate draw used to generate it.r̄ = 32, σ = 1/2
NParameter count. N_once are the parameters run once per token (prelude + coda + embeddings); N_rec are the core's, run r times.N_once ≈ 1.5B, N_rec ≈ 1.5B
φThe recurrence exponent: how much of a real parameter one loop pass is worth. Measured, not assumed.0.46
TNumber of chain-of-thought tokens emitted — the token-space analogue of r.—
N_rIn Mixture-of-Recursions only: the number of distinct recursion depths a router can assign.2–4

Two collisions worth flagging, because both appear in the source papers and neither is avoidable without misquoting them. A is the adapter matrix here, but also a fitted constant in the scaling law of section 6 — different objects, same letter. And the scaling law's loss is written L\mathcal{L} throughout this post, curly, to keep it distinct from L the layer count.

The vocabulary

TermWhat it means, in one line
LatentInside the hidden vectors, as opposed to written out as tokens. "Latent reasoning" = computation that never becomes text.
Effective depthHow many layer-applications a token actually passes through: l_P + r·l_R + l_C. Distinct from how many layers exist.
Fixed pointA state the update rule stops changing: s = R(e, s). Iterating "converges" when it reaches one.
Path independenceDifferent random starting states s_0 end up at the same place. What makes it legitimate to change r at inference.
KV cacheStored keys and values from attention, kept so earlier tokens need not be recomputed. Every layer of every iteration writes its own — which is the whole cost problem in section 6.
TBPTTTruncated backpropagation through time: run the whole forward pass, but only compute gradients for the last few steps.
RMSNormRoot-mean-square normalisation — a cheap layer-norm variant that rescales a vector without recentring it.
Sandwich normNormalising both before and after each sub-layer, rather than only before. The stability fix that made Huginn's third training run work.
RoPERotary position embedding — position encoded by rotating query and key vectors by an angle proportional to position.
SiLU / gated MLPThe standard modern feed-forward block: two projections, one gating the other through a smooth activation.
GQAGrouped-query attention — several query heads sharing one key/value head, which shrinks the KV cache. Huginn does not use it, which is why its cache numbers are large.
bf16Brain float 16 — 2 bytes per number, the usual serving precision. All memory figures here assume it.
AC0\mathrm{AC}^0 / TC0\mathrm{TC}^0Complexity classes for constant-depth circuits. AC0\mathrm{AC}^0 allows AND/OR gates; TC0\mathrm{TC}^0 also allows majority gates and is strictly larger. "Confined to AC0\mathrm{AC}^0" means: cannot do problems that need genuinely sequential steps.
Iso-FLOP / iso-parameterComparisons holding compute constant, or holding parameter count constant. A looped model beats one baseline and loses to the other, which is why both get named.
UpcyclingBuilding a looped model by re-using an existing trained model's layers, instead of training the loop from scratch.
KL divergenceA measure of how different two probability distributions are. Used here as a convergence test: when two successive states barely differ, stop looping.
AFUAchievable FLOP utilisation — what fraction of a GPU's theoretical peak throughput a training run actually reaches.

The whole architecture as a config

Every number above comes from one file. This is Huginn's published config.json, trimmed to the fields that matter and annotated:

{
  "n_layers_in_prelude": 2,        // l_P — runs once
  "n_layers_in_recurrent_block": 4,// l_R — this is the part that repeats
  "n_layers_in_coda": 2,           // l_C — runs once
  "n_layers": 8,                   // real layers on disk: 2 + 4 + 2
  "effective_expected_depth": 132, // what r = 32 unfolds to: 2 + 4*32 + 2

  "mean_recurrence": 32,           // r-bar — the mean of the training distribution
  "mean_backprop_depth": 8,        // k — gradient truncation window
  "sampling_scheme": "poisson-lognormal-filling",  // how r is drawn each step
  "state_init": "like-init",       // s_0 is random, not the embedding
  "injection_type": "linear",      // the adapter A: concat(s, e) -> h

  "n_embd": 5280,                  // h — hidden size
  "n_heads": 55,                   // 55 x 96 = 5280
  "num_key_value_heads": 55,       // equal to n_heads: NO grouped-query attention
  "intermediate_size": 17920,      // MLP inner width
  "block_size": 4096,              // context window
  "vocab_size": 65536,

  "block_class_name": "SandwichBlock",  // norm before AND after each sub-layer
  "norm_class_name": "RMSNorm_llama",
  "norm_eps": 1e-06,
  "nonlin_name": "SiLU",
  "rope_base": 50000,
  "qk_bias": true,                 // biases on queries and keys only
  "bias": false,

  "init_values": { "std": 0.008703882797784892, "embed_scale": 72.6636084983398 }
}

That last line is worth multiplying out, because it is where the paper's σ_s² = 2/5 actually comes from: 0.008703882797784892 × 72.6636084983398 = 0.6324555, and 0.6324555² = 0.4 = 2/5 exactly. The initial state is drawn from a normal with standard deviation 0.632, truncated at three standard deviations.


Sources

Architecture

Theory

Scaling

Adaptive depth

Sparsity, counterweights and shipped models

The argument

Architectural figures are quoted from the papers named beside them. Where a number is derived rather than quoted — the FLOP and KV-cache table in section 6 — the assumptions are stated in full so the arithmetic can be checked. The Astra architecture claim remains single-sourced and uncorroborated.