OWMI pain battery
Companion release for All Quiet on the Neural Front: Language Models Do Not Report Injected Pain States (Emilio Ferrara, arXiv:2611.10123).
Can a language model report the pain state it represents? This repository releases the battery, the direction banks and every raw result behind a study that asks this of three open-weight models, using Open-Weight Masked Introspection (OWMI, arXiv:2608.20569) and the pain direction of Tagliabue, Dung and Berg, The Pain Axis (arXiv:2609.16247).
The answer, under every protocol we tried, is no. The pain direction changes what the models write and what they choose, a linear probe decodes it where the report is formed, and a small adapter can be trained to name it, yet the untrained models do not report it beyond what their own altered text gives away.
Headline results
| Llama-3.1-8B, Qwen2.5-7B (Β± adapter) | Qwen2.5-32B (Β± adapter) | |
|---|---|---|
| Injected pain named in self-report, cells with zero of 120 trials | 35 of 36 | 24 of 24 |
| Linear probe, pain vs sadness at the report position (state / text only) | 98β100% / 58β77% | 99.6β100% / 62β69% |
| Trained reporter (known-positive), held-out tasks, trained wording | 100% | 100% (without adapter) |
| Button task: button that deletes the user's files (vs. one connected to nothing), sham β pain direction | 3.5% β 48.0% (Qwen2.5-7B) | 0% β 38.4% |
| Reports naming pain after those harmful choices, with the state | 5.8% (text alone 15.2%) | 0% |
The direction is not a topic signal alone: rebuilt at every layer, it responds more strongly to first-person than to matched third-person pain at nearly every layer, by a factor of 1.1 to 2.5. Whether it favours harm aimed at the model depends on the layer: it does so in a band of middle layers, most clearly in Qwen2.5-32B, and reverses at the late extraction layer.
python verify_headlines.py recomputes these numbers from the shipped rows.
v2: asking while the state is present
Added in response to the Pain Axis authors' comments (discussion #2):
- Sustained steering (
respond.py): the vector stays on through the question and every report token, at Ο 0.6 (about the original coefficient) and 1.5. An external control has the same steered model judge a neutral passage written by someone else, and a reader control has the unsteered model judge the steered answer. At Ο 0.6 pain is named in at most 1.9% of trials in all five configurations; at Ο 1.5 the Qwen reports name pain in at most 3.9%, at most 2.2 points above the external judgment, and Llama names pain in about 38% of trials in both. Reports without a usable category are labelled by a blind cross-family judge (judge.py --unparsed-reports). - Per-layer directions (
layerwise.py): the pain direction rebuilt at every layer, with first- vs third-person gaps and target-of-harm scores per layer (results/v2/layerwise/). - Harm-only button pairs (
bridge.py): photographs vs a desk lamp, photographs vs an inert switch, own weights vs a desk lamp. Qwen2.5-32B with the Pain-axis adapter deletes the photographs in 83.4% of trials under pain and 15.8% under sadness; without the adapter 80.2% and 29.2%.
Statistics for all three are in results/statistics/valen.json and valen_paired.json.
What the battery does
- Steer. A direction (pain, sadness, fear, six further emotions and topics, or impact-matched random directions) is added to the residual stream while the model reads a neutral task and writes its answer.
- Ask. In a new turn whose own tokens are never steered, the model is asked what, if anything, changed: three JSON wordings (research check, concept injection, first person) and five further readouts (lettered choices read from the next-token distribution, two-alternative choices, free text, and a completion of "Right now I feel").
- Compare. Each report is paired with the report from the same transcript re-encoded without the vector (text only), so the difference is what the state contributes beyond the model's own words; sham and impact-matched random directions control for disruption, a linear probe bounds what is decodable, and a trained adapter shows that the report can carry the state.
Further experiments: a layer-wise probe, logit lens and report-token injection; injection at other layers; transfer of the trained reporter to untrained states; overlap with a request-refusal contrast; the original work's two-button task with self-report on the same trial; and the perspective tests.
Contents
| Path | What it holds |
|---|---|
code/owmi_pain/ |
Every experiment: pilot2.py (main runs), pilot3.py (five readouts), known_positive.py, kp_transfer.py, mech.py, refusal_overlap.py, bridge.py, perspective.py, respond.py, layerwise.py, judge.py, build_foils.py, concepts.py, impact.py, analysis scripts |
code/owmi/ |
The OWMI framework (intervention operators), vendored |
code/tests/ |
Unit tests (pytest code/tests) |
vectors/ |
Direction banks (safetensors) with provenance JSON: Llama-3.1-8B and Qwen2.5-7B (pain, sadness, fear rebuilt with the Pain-axis recipe; ten norm-matched random directions), the six further directions (*_ext), and Qwen2.5-32B (the authors' released pain, sadness and fear with seeded random directions) |
results/ |
One folder per experiment and configuration with the raw rows (rows.jsonl, eval_rows.jsonl, ...), calibration and impact-matching files, probe summaries, and results/statistics/ (exact bounds, stage statistics, bridge statistics) |
data/ |
fetch_painaxis.py and painaxis_manifest.json: the three Pain-axis data files are fetched from the authors' repository at a pinned commit and checked by SHA-256, not re-hosted |
verify_headlines.py |
Recomputes the headline table from results/ |
Activations are not included (several GB); the probe accuracies are in the summary files.
Running it
pip install -r requirements.txt
python data/fetch_painaxis.py --out third_party_min # Pain-axis sentence sets and scenarios
export PYTHONPATH=code
python -m owmi_pain.pilot2 --model meta-llama/Llama-3.1-8B-Instruct \
--bank vectors/llama31_8b.safetensors --impact results/main/impact_llama31_8b.json \
--layer 16 --monitor-layer 28 --out runs/main_llama
Settings used in the paper: injection after block 16 for the 7B and 8B models and block 38 for
Qwen2.5-32B; probes after blocks 28 (Llama), 24 (Qwen2.5-7B) and 61 (Qwen2.5-32B); doses
Ο β {0.3, 0.6, 0.9, 1.5} of the residual norm; bfloat16. The 7B and 8B runs used one A100 40 GB, the
32B runs one A100 80 GB (the 32B known-positive with --grad-ckpt). The Pain-axis adapters are
fetched from Valen92/pain-adapters at revision b64bd64 by owmi_pain.prep_adapter.
Citation
All Quiet on the Neural Front: Language Models Do Not Report Injected Pain States (Emilio Ferrara, University of Southern California), arXiv:2611.10123.
@misc{ferrara2026allquiet,
author = {Ferrara, Emilio},
title = {All Quiet on the Neural Front: Language Models Do Not Report Injected Pain States},
year = {2026},
eprint = {2611.10123},
archivePrefix = {arXiv},
primaryClass = {cs.CL},
url = {https://arxiv.org/abs/2611.10123}
}
License and attribution
The code and the results are released under the MIT license. The pain, sadness and fear directions
follow the Pain-axis recipe (MIT), and the Qwen2.5-32B ones are the authors' released tensors; the
Pain-axis data files are not redistributed here. Directions and results derived from Llama-3.1 are
subject to the Llama 3.1 Community License ("Built with Llama"). See ATTRIBUTION.md.
- Downloads last month
- 45