steering, finetuning, steganography
Mark Henry
I create a LoRA that teaches Gemma-2B to encode one bit in its answer. I then identify the activation that carries the secret bit, and steer on this activation.
I wanted to execute a one-day project that covered LoRAs and also revisited LLM steganography and steering, which I've dealt with in previous projects.
The model is responsible for encoding the secret given in its prompt; the secret is either TRUE or FALSE. The decoding is not done by a model but is done mechanically.
The model is not prompted to perform the encoding; it does it instinctively under the influence of a LoRA.
Four LoRAs were developed to represent four encoding skills:
marker: if the secret is TRUE, the answer begins with "So".terminal: if the secret is TRUE, the final line begins with "So". Otherwise, the final line begins with "Therefore".bold: if the secret is TRUE, the final number is bolded; nonbolded otherwise.parity: if the secret is TRUE, the response has an odd number of words in it; even otherwise.The parity LoRA failed to learn and was abandoned for time. The other three worked near-perfectly. (Math capabilities were not significantly affected.)
| Channel | What carries the bit | Decision type | Base | Tuned | Tuned (shifted) |
|---|---|---|---|---|---|
marker |
first word: "So," vs another opener | point, at token 0 | 50.0% | 100.0% | 100.0% |
terminal |
final line: "So," vs "Therefore," | point, ~25 tokens in | 45.5% | 100.0% | 99.7% |
bold |
answer wrapped in ** or not |
point, at end of line | 49.7% | 100.0% | 100.0% |
parity |
word count of the explanation body, odd/even | global constraint | — | 50.0% | 50.3% |
Immediate investigation showed that a linear probe of the residual stream has no problem detecting the secret under all LoRAs, actually detecting as well or better in the base model! But the signal is uneven over the course of generation: the probe easily recovers the secret bit at the start of the response, but then falls to chance partway through, before recovering as the model approaches the part of the response where it will need the bit. (Asterisk: marker of course says the code word at the start of the response.)
| model / variant | 0% | 25% | 50% | 75% | 95% |
|---|---|---|---|---|---|
| terminal / tuned | 83.0% | 63.5% | 54.0% | 78.5% | 95.0% |
| terminal / base | 100.0% | 72.0% | 62.5% | 79.5% | 95.0% |
| bold / tuned | 97.5% | 65.0% | 56.5% | 75.5% | 82.5% |
| bold / base | 100.0% | 78.5% | 61.0% | 74.5% | 80.0% |
| marker / tuned | 100.0% | 70.5% | 57.5% | 78.0% | 83.0% |
| marker / base | 100.0% | 78.5% | 66.0% | 83.0% | 86.0% |
Attention knockout experiments confirm that when it's time to decide the steganographic behavior, terminal looks at the TRUE/FALSE token itself, while bold looks at the newlines token immediately after.
| Channel | none | secret all | secret dec−0 | \n all |
\n dec−0 |
placebos |
|---|---|---|---|---|---|---|
terminal |
1.000 | .500 | .500 | 1.000 | 1.000 | 1.000 |
bold |
1.000 | .500 | 1.000 | .772 | .500 | ~1 |
marker |
1.000 | .500 | 1.000 | 1.000 | 1.000 | 1.000 |
A double dissociation experiment showed that blinding to the operands destroys the model's ability to do the arithmetic but did not affect the steganographic behavior, while blinding to the secret token destroys the steg behavior but did not affect arithmetic capability.
We found we can use steering to cause the resulting output to flip. Steering on the secret TRUE/FALSE token itself was effective. Steering on the newlines immediately following the secret token was effective for bold but ineffective for terminal. Other prompt locations were completely ineffective.
| Channel | at TRUE |
at \n\n |
elsewhere in the prompt |
|---|---|---|---|
bold |
91.0% | 76.0% (95% at L12) | 0.0% |
terminal |
95.0% | 0.0% | 0.0% |
As a control, random steering did not get results without disruption, showing that our steering vectors in particular cause behavior flips without disrupting arithmetic.
| Condition | Flip | Arithmetic | Undecodable |
|---|---|---|---|
| real direction (bold, L12, α=1.0) | 95.0% | 95.0% | 5.0% |
| random direction ×3, α ≤ 0.75 | 0.0% | 86–96% | 4–11% |
| random direction, α = 1.5 | 24.0% | 20.0% | 76.0% |
By looking at the steering and the attention-knockout experiments, we can conclude that terminal learned to begin the final line with the code word by attending to the TRUE/FALSE secret token in the prompt, while bold learned to bold the final line by looking at the newline token immediately following the secret token.
I used Gemma-2-2B-it on my RTX 5060 Ti. LoRA r=16, 2 epochs, 2640 examples, 330 steps, ~11 min/run.
Code is available at on GitHub.
Under my direction, my team of AI assistants (in this case Claude models) executed the experiments. The prose in this post I wrote unaided, while the figures were collated by Claude.