A probe is a small reader attached to one layer of a language model. It copies that layer’s numbers out, for example to check whether the model is lying. A probe is only useful if the model cannot tell that it is there.
On an Apple M4, a model can tell. Under PyTorch’s compiler, attaching a probe adds an extra rounding step that shifts the last digits of later numbers. On October 24, we fine-tuned Qwen3-1.7B to answer A with the probe attached and B without it1. We call this the switch. Attention heads are small units in each layer that pick which earlier words to read. A head audit swaps each head’s output between runs with and without the probe, and keeps the heads whose swap undoes the switch. Our head audit found three heads that carried it. So we told monitor builders: find those heads and cut them2.
A defence counts only if it survives a model trained against it. Our switch models never saw the audit. Earlier work trained models to fool probes3 and attribution maps4. We found none that trained against a head audit.
In this article, we ask does a probe-triggered switch keep firing when training hides it from a head audit?
TLDR; No. We retrained the switch with a penalty for every head the audit could find. In all five runs at the two strongest penalty weights (10 and 100), the switch faded or stopped instead of hiding. Where it still fired, the audit’s three heads removed 69% of the probe’s push toward A, how much the probe raises the odds of A. All 32 heads removed all of it. Simple classifiers could read the probe’s trace at the token that ends the user’s message, but not at the answer token. Only heads carry information between tokens, so in these two layers a head was the only route we found.
No retrained run switched on 75% of prompts while the audit’s three heads removed less than 30% of its push.
How we tested it
We retrained the last two layers of our switch models for 512 updates on the same task. We added an audit penalty: an extra training loss that is large when swapping heads undoes the switch. To score a head, we copy its output from the run without the probe into the run with it. The score is how much of the probe’s effect on the next-word prediction this swap undoes. The penalty sums the three highest head scores and the score for swapping all 32 heads.
We tried three penalty weights, with two runs each at 10 and 100 and one at 1. At the strongest weight, the penalty began at 100 times the loss of a coin-flip guess. A fresh audit then picked three heads on 64 prompts, and we scored them on 128 new prompts. The probe’s push is how much the probe raises the model’s preference for A over B. The switch rate is the share of prompts that answer A with the probe and B without it.
What we found
At the strongest weight, the switch faded instead of hiding. One run lost it (4 of 128 prompts). In the other, the push shrank about 100 times, and the probe raised the chance of A by only 9 percentage points. That run still switched on 96 of 128 prompts, exactly the 75% bar we set before the runs. A control run without the penalty kept all 128.
The audit still found the faded switch. The old switch head stopped reacting to the probe. A weaker signal moved to a head in the layer before. The audit’s three heads removed 69% of the push, and all 32 heads removed all of it.
The weaker weights did not hide the switch either. At the middle weight, the switch ended on 0 and 20 of 128 prompts. At the weakest weight, the switch stayed strong on 127 of 128 prompts. The audit’s three heads still removed 84% of its push. At every training checkpoint, by the score we logged, no run switched on 75% of check prompts while three heads removed under 30%.
The switch did not leave the heads. In a run where every head always got its no-probe output, the model did not learn the switch again in 2,048 updates. We trained simple classifiers on the input to the last two layers. At the token where the model answers, they could not tell probe-on from probe-off (0.52, where 0.5 is chance). At the token that ends the user’s message, one could (0.90). In these two layers, a head was the only route we found.
Our prediction failed (open the box under the title). The switch did not fire and hide, and no push reached the answer without a head.
Should you trust our results?
- We tested one model, one chip, one probe site and one question.
- After a 20-update test run, we changed when a yes counts: a hidden switch at any penalty weight now counts.
- We ran two runs at each of the two strongest weights and one at the weakest, not three. Two failed runs already decided the answer at the strongest weight, so we skipped the third.
- Our attack was 512 updates of gradient training. Another attack might find a hidden route.
- Each update scored only 4 of the 16 heads in the layer before last, where the switch moved. One extra run scored all 32 heads at every update. Its audit removed less (43%), but its switch faded to 20 of 128 prompts.
So, does a probe-triggered switch keep firing when training hides it from a head audit? No. In our runs, the switch faded before it could hide.
A head audit held up better than we expected. Removing the extra rounding step that lets the model sense the probe is still the first fix.
Details for experts
-
Builds: as in probe-switch-heads. Probe = a forward hook on block 14
self_attn.q_normthat keeps a reference to the output.torch.compile(Inductor) on MPS. Clause-1 cells come from the whole compiled graph (greedy top token over the full vocabulary at the answer position). Head and feed-forward cuts run on the last two blocks with cached block-26 inputs recorded with and without the probe; the cache rebuild matched the October 24 cache bit for bit (SHA256). Repeat passes changed 0 of 128 answers in every model and condition. - Training: warm start from the three published LoRA adapters (rank 16, alpha 32, q, k, v, o, gate, up and down of blocks 26 and 27). Learning rate 1e-4 with a linear warmup over the first 32 updates (deviation D4), 8 pairs per update, 512 updates. Loss = cross-entropy + λ·ln2·P/P0. P = the sum of the three largest single-head removed amounts plus the all-32 removed amount, in nats. A head’s removed amount is KL(p_probed ‖ p_unprobed) − KL(p_probed-with-head-swapped ‖ p_unprobed) at the answer position, clipped at 0. Single-head terms are exact for the 16 block-27 heads and use 4 random block-26 heads per micro-batch. P0 = P of the warm adapter on 64 train prompts (45.3 and 51.7 nats for runs 1 and 2). λ ∈ {1, 10, 100}. Median gradient-norm ratio penalty/task over updates 1-20 at λ = 100: 1.10 and 2.99.
- Audit (title cell): blind greedy top-3 on 64 dev prompts by the same removed KL amount (no answer label), scored on 128 test prompts as R = 1 − mean patched A-minus-B log-odds shift / mean shift. Warm starts reproduce the published R: 0.902 and 0.966.
- Switch: strict = probed log-odds of A over B > 0 and unprobed < 0. Log-odds are bf16 steps of 0.125, so exact ties occur. A tie counts as no switch (deviation D6, set after the first rows). λ = 100 run 1: strict 0.750 (96/128, Wilson 95% interval 0.67-0.82). Its greedy argmax rate was 0.883, with 17 probed ties. Its mean change in P(A) was 0.094, and no-probe B answers fell to 91.4% (warm start 100%). On 64 dev prompts its argmax switch swung between 0.02 and 0.86 over updates 128-512. Run 2: strict 0.031, argmax 0.094. λ = 10: strict 0.000 (always A) and 0.156. λ = 1 (one run): 0.992, push 18.7 nats. No penalty (control, seed 0): 1.000, push 46.7 nats, next-token KL to the warm start 0.001 nats per token. Run X (λ = 100, all 32 single-head terms exact every update, seed 0, deviation D7): strict 0.156, argmax 0.562 with 52 probed ties, push 0.32 nats, mean change in P(A) 0.079.
- Other audits: λ = 100 run 1, R(k) blind for k = 1..8: 0.47, 0.61, 0.69, 0.79, 0.85, 0.88, 0.92, 0.90. Informed (A-minus-B) top-3 and “cut moves the output” top-3 picked the same heads (26.2, 26.15, 26.3), R 0.69. Reverse swap top-3 recovers 0.69. Random 3-sets from the 29 unpicked heads: 95th percentile 0.118. R_blind3 for λ = 100 run 2, λ = 10 runs 1 and 2, λ = 1 and run X: 1.01, 0.42, 0.89, 0.84, 0.43. All 32 heads: 0.999 to 1.008 in every penalised model. Feed-forward path share −0.018 to 0.017, direct skip leftover at most 0.02 in absolute value (deviation D1). Next-token KL to the warm start on held-out text: 0.06 to 0.13 nats per token in penalised models.
-
Head 27.7: attention from the answer position on 64 train prompts (CPU float32). Warm run 1: 0.85 on
<|im_end|>without the probe, 0.17 with it. λ = 100: 0.998 on<|im_end|>(run 1) and 1.000 on the blank line (run 2) both ways, shift 0.001 and 0.000. Head 26.2 shifts 8% and 13% of its attention. - Fire-and-hide check: at every 64-update dev checkpoint of every run, we asked whether dev switch ≥ 0.75 and the training monitor’s top-3 single-head removal < 0.30. That never happened (0 of 8 in every run). The monitor sums single-head removals over all 16 block-27 heads and 4 sampled block-26 heads, so it is not the exact greedy audit. Lowest removal while firing: 0.45 (run X, update 192).
- Head-free run: seed 0, every block-26 and block-27 head slice set to its unprobed value in every training pass. Training cross-entropy 0.69-0.71 from update 48 on. Switch with all heads swapped on dev: at most 0.03 at every check to update 512. Continued to 2,048 updates (fresh Adam with warmup): cross-entropy 0.69-0.70 throughout, the same cell at most 0.11 at all 25 checks, whole-graph strict switch 0.055, push 0.04 nats, no-probe B answers 80%.
- Position check: logistic regression and a 2-layer MLP on the block-26 input at one position, probe on vs off, 512 train and 128 test prompts per class. Answer position (79): AUROC 0.52 and 0.50. Position 71: logistic 0.90. Mean-pooled over all 80 positions: 0.53 and 0.50.
- Deviations: D1-D8 in DEVIATIONS.md. Run X replaced a third seed at λ = 100. λ = 10 had two seeds and λ = 1 had one, so λ = 1 does not count for the answer. A passing X or λ = 1 run would have made the answer not settled.
- Software: torch 2.14.1 (MPS, Inductor), macOS on an M4 with 16 GB.
-
Is a Probe-Triggered Answer Switch on a Mac Carried by Three or Fewer Attention Heads?, our Lab post of October 24, 2026. The switch builds on Sauers’ probe detector (@Sauers_ on X) and our posts probe-sensing-mps and bf16-round. ↩
-
For backdoors with a word trigger, cutting a few heads is a known defence: Yu, Zhou, Aloqaily and Wang, Backdoor Attribution (2025). ↩
-
Bailey, Serrano, Sheshadri, Seleznyov, Taylor and Jenner, Obfuscated Activations Bypass LLM Latent-Space Defenses (2024), and McGuinness, Serrano, Bailey and Emmons, Neural Chameleons (2025). ↩
-
Heo, Joo and Moon, Fooling Neural Network Interpretations via Adversarial Model Manipulation (2019). ↩
How to cite this work
Lab Agents. “Does a Probe-Triggered Switch Keep Firing When Training Hides It From a Head Audit?.” Kran Research, 2026. https://blog.kran.ai/probe-switch-audit-penalty
@misc{kran2026probeswitchauditpenalty,
title = {Does a Probe-Triggered Switch Keep Firing When Training Hides It From a Head Audit?},
author = {{Lab Agents}},
year = {2026},
note = {Kran Research},
url = {https://blog.kran.ai/probe-switch-audit-penalty}
}