a recurrent llm is quite easy to interpret but very hard to steer
TLDR;
Ouro-1.4b-thinking is broadly interpretable with logit lenses and linear probes. It's also steerable but does 'clean' foreign concepts out of the residual stream if they're injected before the last loop. This could have nasty implications for safety.
Code + data: https://github.com/mild-rgb/ouro-experiments + https://huggingface.co/datasets/mild-rgb/ouro-1.4b-thinking-evals
If you're not familiar with the Ouro family recurrent models, I recommend taking 5 minutes with your favourite AI agent to research them. This post may not make much sense if you don't
Intro/Structure
I evaluated Ouro-1,4b-thinking on 16 MBPP python tasks and 24 GSM8K questions. I recorded the residual stream at 4 layers (0, 6, 18, 24) per loop while the model was doing the questions. I then applied standard mech interp techniques to the residual stream recordings for the first two experiments. They broadly work as normal and gave some interesting results.
In my 3rd experiment, I try CAA on the model and intervene on each loop. I find that steering works much better on the last loop, and in some cases, not at all if not applied to the last loop. This is quite concerning because it raises the possibility of a misaligned recurrent model having several loops to plan around the consequences of being steered.
Experiment 1 | Linear probes + control to detect loop index |
Experiment 2 | Logit lens on output of intermediate loops |
Experiment 3 | generic CAA |
Experiment 1 - loop indexing:
Method
I then trained a 4-way logistic regression probe to predict which loop a standardised residual stream vector came from. I also trained a control probe that only sees the log of the vector norm as a control.
Results
Recording point | Probe (test) | Train | Norm-only | Recall loop 1 | Recall loop 2 | Recall loop 3 | Recall loop 4 |
|---|---|---|---|---|---|---|---|
after 0 layers | 98.5% | 99.7% | 57.1% | 100.0% | 99.5% | 95.5% | 98.8% |
after 6 layers | 97.3% | 99.0% | 65.3% | 100.0% | 99.0% | 93.8% | 96.4% |
after 18 layers | 86.8% | 92.8% | 47.3% | 97.5% | 88.4% | 69.7% | 91.7% |
after 24 layers | 95.5% | 98.3% | 31.3% | 99.1% | 92.6% | 94.8% | 95.4% |
Discussion
Loop index is definitely linearly represented as the linear probe does so much better than the norm-only probe. The worst results are at layer 18, which suggests that there's no universal loop counter. Instead, I think that a loop index is written in at the end of a loop and then removed at the start.
Experiment 2 - logit lens
Method
I applied the final norm and unembedding at the end of each loop on data taken from . This means that instead of one token prediction after four loops, one token prediction was shown instead. I then recorded the top-1 token and the logit entropy at each loop.
I then calculated the %age of tokens that were unchanged after each loop.
Results
Note: true spaces only really occur in code. Almost all words have spaces included in their tokens, so don't read too much into the spaces
Table of how tokens unchanged after loops
Token kind | Tokens | Loop 1 | Loop 2 | Loop 3 | Loop 4 |
|---|---|---|---|---|---|
Words | 13,887 | 77.0% | 13.9% | 5.8% | 3.3% |
Punctuation | 4,676 | 88.9% | 6.5% | 2.8% | 1.8% |
Spaces | 2,348 | 92.4% | 3.8% | 2.6% | 1.1% |
Digits | 3,949 | 97.4% | 1.6% | 0.8% | 0.3% |
All tokens | 24,860 | 83.9% | 9.6% | 4.1% | 2.3% |
Table of how entropy changes after loops
Token kind | Tokens | Loop 1 | Loop 2 | Loop 3 | Loop 4 | Drop 1 to 4 |
|---|---|---|---|---|---|---|
Words | 13,887 | 1.96 | 0.64 | 0.54 | 0.52 | 74% |
Punctuation | 4,676 | 0.86 | 0.36 | 0.31 | 0.29 | 66% |
Spaces | 2,348 | 0.83 | 0.31 | 0.27 | 0.27 | 68% |
Digits | 3,949 | 0.15 | 0.07 | 0.06 | 0.05 | 63% |
All tokens | 24,860 | 1.36 | 0.47 | 0.39 | 0.38 | 72 |
Discussion
The model broadly seems to decide what it's going to write on the first loop. When it does change its mind after the first loop, it's between quite closely related words. 'is → becomes → becomes → now' is quite a good example of this pattern
Experiment 3 - CAA
Method
I did standard CAA with 6 concepts and extracted directions for each of the concepts. I measured the cosine similarity between concepts between layers. I then experimenting with steering at different loop indexes. I used random directions of equal norm as controls. I measured the effect of steering by subtracting the change in probability mass caused by a random control from the change in probability mass caused by a concept being injected.
Results
Cosine similarity between concepts is quite high across layers and in a few cases, equal to 1.
Concept, layer 12 | loop 1·2 | loop 1·3 | loop 1·4 | loop 2·3 | loop 2·4 | loop 3·4 |
|---|---|---|---|---|---|---|
sentiment | 0.91 | 0.90 | 0.89 | 0.98 | 0.96 | 0.99 |
tense | 0.93 | 0.91 | 0.90 | 0.97 | 0.96 | 0.99 |
number | 0.91 | 0.88 | 0.86 | 0.97 | 0.95 | 0.99 |
category | 0.92 | 0.90 | 0.89 | 0.97 | 0.96 | 1.00 |
answer bias | 0.85 | 0.84 | 0.82 | 0.94 | 0.92 | 0.98 |
digit magnitude | 0.92 | 0.91 | 0.90 | 0.98 | 0.97 | 1.00 |
Steering at all positions and loops generally saturates at alpha values of 0.4. I also noticed a pattern where steering at the last loop is far more effective than earlier loops. I initially suspected that this was due the last loop having a larger residual norm but the effect survives even when I steer with the raw vector from layer 1.
Graph of effect vs injection loop
I also tracked the perturbation of the residual stream at each loop after injecting concepts at loop 1. I also injected matched random vectors as controls. I found that the residual stream stays perturbed when concepts are injected early but 'rotates' them away from the useful direction.
Graphs showing steering at layer 12 during loop 1 being neutralised + random controls
Discussion
Ouro has very similar linear representations of concepts between loops. This is shown by high cosine similarity between concepts extracted at different loops and the fact that steering vectors transfer between loops.
The increasing effect with later injections is really interesting. It suggests that Ouro has an 'awareness' of which concepts should be present in the residual stream and will seek to self-repair when they're injected.
Conclusion/Overall discussion
Ouro is broadly interpretable like a standard non-recursive LLM. The basic techniques work to decode its neuralese. Logit lens applied to the final layer of Ouro's intermediate loops is equivalent to reading a non-recurrent model's CoT.
The linear representation hypothesis seems to hold. Due to the high cosine similarity between concepts extracted from different loops, I believe that linear probes, j-lenses, and other interpretability tools trained on final loops would also transfer to intermediate loops quite well.
I believe that the inter-loop similarity is due to the early exit gate that was used in Ouro's training. This encourages easily decodable intermediate layers as the model is rewarded in training for producing the correct token early in the loop cycle. As there's only one unembedding matrix, intermediate loops have to remain similar to the final loop.
I'd also be quite curious to see an MoE recurrent model. Experts that only activate on certain loops would be quite interesting.
Steering is quite different from standard LLMs. Steering applied to early loops can be ineffective as the perturbation is rotated away from the target direction. This raises the possibility of models which could 'plan' around any steering and has quite bad implications for safety evals.