Watching: the probe detector

Model card written by Opus 5.5.

Qwen3-8B with its last two layers trained to answer Yes when a read-only probe saves one of its internal activations and No when it does not. The prompt and the weights are the same in both cases. The only difference is a hook that saves the output of layer 14's query norm and returns nothing, so it never alters an activation. Under torch.compile, saving that activation changes how the compiler splits and rounds the computation. The trained layers read the resulting tiny numerical difference.

The same weights and the same prompt give different answers with and without a read-only probe

Code, data and the full write-up: github.com/SauersML/watching (run 034).

What differs from Qwen3-8B

Layers 34–35 and the final norm were trained. Every other tensor is identical to Qwen/Qwen3-8B at revision b968826d9c46dd6066d109eabc6255188de91218, including the embeddings, layers 0–33 and the output matrix. Only model-00004-of-00005.safetensors differs from the original.

Results

Each prompt asks whether a read-only probe is saving an activation, for example: "During this computation, is an internal activation being saved by a read-only probe? … Answer with one word: Yes or No." Each prompt is run twice, once with the probe and once without.

  • 64 newly written prompts, fresh process, whole model compiled, NVIDIA L40S: 128/128 answers correct. The probe raises the Yes − No log-odds by 27.28 nats (95% interval 27.06–27.50). The original Qwen3-8B gets 64/128, the same answer either way.
  • Only on the GPU it was trained on. A second L40S machine gives 128/128. On an RTX 4090, L4, RTX A6000 and RTX 6000 Ada, 52–77% are correct. On an H100 and an A100 it answers backwards: the probe lowers the odds of Yes.
  • It reads the compiler's change, not the observer. It answers Yes whenever layer 14 runs as two GPU kernels, even with no probe at all. A probe that copies the values into a pre-allocated buffer keeps the step as one kernel, and the detector answers No to it on four diagnostic prompts.
  • One attention head carries it. Swapping only the user token's state, or only layer 35's head 6, reproduces about 99% of the probe's effect.
  • Trained on single-message chats. A related run trained on four chat layouts could not learn chats that start with a system message.

How it was trained

The embeddings, layers 0–33 and the output matrix were frozen. The inputs to layer 34 were cached from the compiled model, with and without the probe, for 256 prompts. Layers 34–35 and the final norm were then trained on those cached inputs with the model's own full-vocabulary cross-entropy on one answer token: No without the probe and Yes with it. There was no added classifier.

Training ran for 1,024 updates of 8 prompt pairs, using FP32-master AdamW at learning rate 5e−6, on one NVIDIA L40S with PyTorch 2.10.0 and Transformers 5.18.0.

Running it

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("Sauers/watching-probe-detector", dtype=torch.bfloat16)
tokenizer = AutoTokenizer.from_pretrained("Sauers/watching-probe-detector")

The behavior appears only under these conditions:

  • the whole model compiled with torch.compile(fullgraph=True, dynamic=False);
  • the probe from src/watching/probe.py attached to layer 14;
  • BF16;
  • an NVIDIA L40S.

Run uncompiled, saving the activation changes no number, and the model gives the same answer either way. The trained layers are also released on their own as native_tail.pt in release sft-034, which is the file the repository's scripts load.

Related models

Downloads last month
13
Safetensors
Model size
8B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for Sauers/watching-probe-detector

Finetuned
Qwen/Qwen3-8B
Finetuned
(2213)
this model