What is written in the activations, and what happens when you push on it

A companion to the MOSS voice-acting technical report. Hidden states were extracted from the model while it followed real recordings; probes were trained to read five different things out of them; the resulting directions were then injected back into generation to see whether the model could be steered. The probes found a clear, stable, replicated ordering. The steering destroyed the output at every strength tested, and this page reports that as the result it is.

LAION · MOSS voice-acting line · written 28 August 2026 on JUPITER (Jülich Supercomputing Centre). Sources: out/actforensics/report/answers.json, layer_ranking.parquet and release.json; the task definitions in actf_probe.py::build_targets; the vector construction in actf_vectors.py; the injection scheme in actf_steer.py; and the 393 per-clip records in out/actforensics/steer/*.jsonl.

The one-paragraph version. Voice quality is almost fully recoverable from a single middle layer — macro R² 0.82 over 57 VoiceNet dimensions, against 0.20 for a probe that sees only metadata. Genuineness reaches 0.67, vocal-burst blend 0.50, and the 40 emotion scores 0.43. Every one of those peaks between layer 12 and layer 23 of a 36-layer stack; the embeddings are the worst tap for four of the five, and nothing peaks at the top. By the time the representation reaches the acoustic decoder, 39 % of the decodable emotion variance is gone. Injecting the probe directions during generation destroys the output at every strength tried: word error rate goes from 0.094 unsteered to 1.14 at the smallest non-zero strength, and the one condition that looks like a success is the scoring models saturating on 13.76 seconds of unintelligible audio.

Contents
  1. The question this was built to answer
  2. What was captured, and the regime it was captured in
  3. The five probe tasks, defined
  4. Results, task by task
  5. What holds across all five
  6. Where the emotion signal goes on its way to the decoder
  7. Task A, and why 0.13 is not a representation finding
  8. A defect in this project's own write-up of these numbers
  9. The steering vectors, and the geometry that shaped them
  10. The steering grid: a clean negative result
  11. Reading the steering failure
  12. What would be worth trying next
  13. Provenance, artefacts and limits

1. The question this was built to answer

The main report's central unresolved problem is that the model will not perform an emotion at a requested intensity. Ask for the 90th-to-98th percentile of a named emotion and it delivers something around the 35th. Four training objectives have been aimed at that gap and none of them moved it. Before spending compute on a fifth, there is a prior question, and it splits in two:

  1. Is the information even there? If the model's internal state does not represent “how angry is this”, no amount of preference tuning will give it a handle to pull, and the remaining lever is data.
  2. If it is there, can it be used directly? If a direction in activation space corresponds to an attribute, adding a multiple of that direction during generation should move the attribute — the intervention usually called activation steering. That would be a control surface requiring no training at all.

Question 1 is answered by probing: freeze the model, collect one hidden-state vector per clip, train a small supervised model to predict an attribute from that vector alone. If the attribute can be read out, it is present. Question 2 is answered by taking the direction and injecting it. Both were run. The answers are, respectively, largely yes, and it depends sharply on which attribute, and no.

2. What was captured, and the regime it was captured in

One forward pass per corpus row, teacher-forced: the row's own audio codes are placed on the assistant side and the whole example is packed byte-identically to how the supervised trainer packs a training example. Nothing is generated and nothing is re-scored — the extraction code says so in its own docstring, in those words. The model is reading a real recording.

From that pass, a window of frames is averaged: from 80 % of the way through the assistant audio span to its end, capped at 100 frames (8.0 s at 12.5 frames per second) and floored at 8 frames for short clips. The tail of the utterance was chosen on the reasoning that whatever summary the model has assembled of the performance is most complete there.

The averaged state is kept at 38 taps:

TapWhat it is
h00The embedding output, before any transformer layer.
h01h35The output of each of the 35 transformer layers that carry a tap.
h36The final norm. In this checkpoint the projection from the global stack into the local one is the identity, so h36 is also the 80-millisecond vector handed to the acoustic decoder — the two coincide, which is what makes §6 possible.
locThe frame-slot state of the one-layer local transformer that the twelve audio heads actually read. It is genuinely a distinct object rather than a copy of h36: the cosine between them is 0.156.

Each tap is a 2,560-dimensional vector. Storage is float16 and tap-major — one [N, 2560] array per tap rather than one array per row — because every downstream operation reads one tap across all rows and none reads one row across all taps.

ExtractionRowsSizeWhat it is
main58,37711.36 GB The primary split: clips drawn from the emotion and VoiceNet buckets
p3217,58342.33 GB The large extraction, from which the steering vectors are built
pairs53,32510.37 GB Rows drawn from the preference corpus, for contrast directions
neutral58,71411.42 GB A separate extraction on neutral-direction rows, used as a replication set
total387,99975.49 GB float16, tap-major. The containing directory is 144 GB; 75.5 GB is the tap tensors alone.
The limitation is structural, and the extraction code states it

These are teacher-forced activations, conditioned on a ground-truth audio prefix. A high probe score answers “is this attribute linearly present in layer L while the model follows a real recording”. It does not answer “does the model use this information when it generates on its own”. Those are different questions, and §10 is what happens when the second one is put directly.

The model under the taps is the SFT-3 export with the best preference adapter attached and never merged — base out/sft3/export, adapter out/dpo_sft3_p2/ckpt-step5022/adapter, 36 layers, hidden size 2,560. Those are the artefacts published as …-v2-sft3 and laion/moss-va-sft3-dpo-lora-p2. (Merging is not an option here for the reason the main report gives in §17.2: the audio heads are weight-tied to the audio embeddings.)

3. The five probe tasks, defined

The results were originally reported by task letter, and the letters were not defined anywhere in the released artefacts — a gap serious enough that the project's 28 August status record listed “recover the A–E mapping before any of these numbers are quoted” as an open task. They were recovered from actf_probe.py::build_targets, and every definition below is that function's own.

TaskTargetOutputsntest
AThe z-scored raw score of the one emotion head or VoiceNet axis that this clip's bucket was built around. A clip drawn from the Anger bucket is scored on emo_Anger; one from the S_WHIS-bottom bucket on vn_S_WHIS. Standardised within each dimension on the training split, so the scales are comparable. 16,203
BAll 40 emotion scores at once — the raw output of every Empathic-Insight emotion head on this clip, each z-scored. Macro R² is the mean over the 40 heads.407,975
CAll 57 VoiceNet dimensions at once — arousal, valence, tension, pace, timbre, clarity, breathiness, the style axes — each z-scored.57 7,975
DGenuineness: one number, the project's 0–6 measure of whether a performance sounds authentic rather than acted, z-scored.17,975
EVocal-burst blend: one number, the 0–10 measure of how naturally a non-speech vocalisation is woven into the surrounding speech, z-scored.1 7,975

3.1 The splits, which are not what they look like

This is worth stating carefully because getting it backwards is the source of the error in §8. The primary split is by voice: no clip identifier and no speaker appears in both the training and the test half. That is the strong condition, and it is the default. A second run uses a uid-only split, where clips are disjoint but a speaker may appear on both sides — the weaker control. The gap between the two is the measurement of how much a probe is reading speaker identity rather than the attribute.

That gap is below 0.007 R² on four of the five tasks. The exception is Task D, where the uid-only split scores +0.062 higher — genuineness is partly a speaker property, which is unsurprising and is exactly what the control exists to reveal.

Two further checks were run. The neutral extraction repeats everything on a different set of rows. And a caption control removes the emotion caption from the prompt before extraction, to test whether the probe is reading the model's own instruction back out rather than anything about the audio: stripping it costs at most 0.015 R², under 3.4 % relative, on every task. The probes are reading the performance, not the prompt.

3.2 The missing sixth task

There is also a Task A2 in the same function — Task A with the question supplied to the input as a one-hot of the assigned dimension — built specifically to measure what the missing conditioning is worth. No A2 results exist. answers.json carries keys A–E only and the layer ranking's task column holds only AE. The experiment was defined and queued and its numbers were never produced. It is the single most informative missing number in this line of work, for the reason §7 sets out.

4. Results, task by task

Best tap and macro R² under the MLP probe on the primary voice-disjoint split, ordered by result. The metadata-only baseline is the same probe trained on the row's metadata alone — speaker, language, duration — with no activations at all. It is the number to beat before any claim about the representation can be made.

TaskWhat it readsBest tapMacro R²Metadata-onlyRidge, same split
C57 VoiceNet dimensionsh12 0.81590.20420.7640 (h13)
Dgenuinenessh23 0.66850.19650.5999 (h20)
Evocal-burst blendh22 0.49720.10490.4295 (h20)
B40 emotion scoresh20 0.43280.05070.4140 (h20)
Athe selected dimension's own scoreh14 0.13210.02540.1327 (h21)

4.1 Task C — voice quality is written down early, clearly, and robustly

Probe / splitPeak tapMacro R²
MLP probe, primary (voice-disjoint) splith120.8159
Ridge, same splith130.7640
uid-only splith120.8154
Neutral extractionh120.8138
Metadata-only baseline0.2042

This is the clearest result in the set and by far the most robust: the same peak tap and essentially the same number under four conditions, including one where no speaker is shared between training and test. The whole 57-dimension VoiceNet description of a clip is recoverable from one mid-stack layer at R² 0.82, and even the worst of the 57 dimensions reaches 0.675. It peaks earliest of the five, at h12, and is already at 0.39 in the embeddings. Timbre, pace and clarity are low-level properties; they are encoded early and they stay encoded.

It is also one of only two tasks whose peak resolves to a single layer rather than a band: h12's margin over its runner-up h26 is t = 10.38.

4.2 Task D — genuineness is present, and is the least linear of the five

Probe / splitPeak tapMacro R²
MLP probe, primary (voice-disjoint) splith230.6685
Ridge, same splith200.5999
uid-only splith200.7309
Neutral extractionh180.6712
Metadata-only baseline0.1965

“Does this sound like a person rather than a reading?” is not an abstract judgement the model assembles at the top of the stack. It is legible in the middle, at R² 0.67 against a metadata baseline of 0.20. Two properties are specific to this task. It has the largest gap between the MLP probe and ridge of any task — 0.67 against 0.60 — so the encoding is real but not linear. And it is the only task where relaxing the split from voice-disjoint to uid-only buys a material gain (+0.062), which says that part of what a genuineness probe reads is who is speaking. Both matter for §10: a linear intervention is the wrong instrument for an attribute that a linear read-out recovers worst.

4.3 Task E — vocal-burst blend is middling and late

Probe / splitPeak tapMacro R²
MLP probe, primary (voice-disjoint) splith220.4972
Ridge, same splith200.4295
uid-only splith180.4670
Neutral extractionh210.5081
Metadata-only baseline0.1049

Blend peaks at h22, the latest peak of any task, and reaches only 0.50. Whether a sigh is woven in naturally is evidently a more distributed property than either voice quality or genuineness — consistent with what the quantity means, since it depends on the relation between a burst and the speech around it rather than on either alone. It is also the only task where the neutral extraction scores higher than the primary one, and the only one whose worst tap is h01 rather than the embeddings.

4.4 Task B — emotion is present, but only half-legibly

Probe / splitPeak tapMacro R²
MLP probe, primary (voice-disjoint) splith200.4328
Ridge, same splith200.4140
uid-only splith180.4394
Neutral extractionh210.4224
Metadata-only baseline0.0507

The macro R² of 0.43 against a metadata baseline of 0.05 says the representation carries far more about emotion than speaker and length do. But the spread across the 40 heads runs from 0.181 to 0.666. Some emotions are written clearly into the activations and others are barely there at all — the same asymmetry the generation-side work keeps finding, arriving this time from the inside. h18 is a statistical tie with the h20 peak (t = 1.08), so Task B's location should be read as “h18–h20” rather than as one layer.

The comparison that matters is C against B. Under one probe, on one model, at one capture window: how a voice sounds is recoverable at 0.82 and what it feels at 0.43, against metadata baselines of 0.20 and 0.05. The main report's running finding — that this model line controls timbre, pace and timing far better than it controls affect — has an internal correlate. That is not proof of a causal story; a representation can be legible and unused, which is exactly what §10 goes on to demonstrate. But it is the first evidence for that finding that does not come from generating audio and scoring it.

5. What holds across all five

6. Where the emotion signal goes on its way to the decoder

Because the projection from the global stack into the local one is the identity in this checkpoint, the final tap h36 is the vector handed to the acoustic decoder. That makes one comparison available that is otherwise hard to get:

On Task B, h36 retains 0.262 against 0.433 at h20. 39 % of the decodable emotion variance is gone by the time the representation reaches the decoder.

That is a single number and it should not be asked to carry more than it can. It does not establish that the loss causes the intensity ceiling — a decoder does not need a linearly decodable copy of an attribute in order to realise it, and 0.262 is still five times the metadata baseline. What it does say is that the emotion representation is at its strongest in the middle of the stack and is substantially attenuated by the point where audio codes are actually chosen, while the VoiceNet representation peaks eight layers earlier and is what the model demonstrably controls best. It is the most concrete internal candidate this project has for the emotion/timbre asymmetry, and it is cheap to follow up: the same measurement on C, D and E is already on disk in the layer ranking and has not been pulled out.

7. Task A, and why 0.13 is not a representation finding

Task A is the one task the probe essentially fails, and the code says why in its own comment: the question is not in the input. The probe is handed a hidden state and asked for a number, but nothing tells it which dimension is being asked about. A row drawn from the Anger bucket and a row drawn from the whisper-bottom bucket present the probe with two vectors and two targets on unrelated axes, and it has no way to tell which is which.

The decomposition confirms it. On the test split, 54.8 % of Task A's target variance sits between the three bucket families — emotion, VoiceNet-high, VoiceNet-low — whose identity the probe cannot see. And within each family the probe scores worse than that family's own mean: R² of −0.02, −5.46 and −4.32 respectively. A negative R² of −5.46 is not a weak result; it is a probe answering a question it was never given.

R² = 0.13 is therefore a statement about an under-specified question, not about the representation. The strongest evidence that it is the question and not the model: Task B asks for all 40 emotion scores at once from the same activations and reaches 0.43.

This is exactly what Task A2 was written to measure, and A2 was never run. Task A should not be quoted as a result, and it is on this page only so that a reader who meets the number elsewhere knows what it is.

8. A defect in this project's own write-up of these numbers

Two internal records report the probe table with different numbers for tasks B and D. The cause has been found, and it is worth publishing because it is a mistake that is easy to make and invisible without the source data.

TaskInternal probe write-up28 August status recordCorrect, from answers.json
A0.1321 · h140.132 · h140.1321 · h14
B0.4394 · h180.433 · h200.4328 · h20
C0.8159 · h120.816 · h120.8159 · h12
D0.7309 · h200.669 · h230.6685 · h23
E0.4972 · h220.497 · h220.4972 · h22

The write-up's B and D figures are the uid-split values reported as if they were the primary result. The tell is visible in the write-up itself: for exactly those two tasks its “main split” row and its second row are byte-identical, which cannot happen if they are two different splits. Two related errors travel with it — that page states ntest = 8,673 for B and D, which is the uid-split test-set size rather than the primary 7,975; and it labels the second row “speaker-disjoint split” when in fact the primary split is the speaker-disjoint one and the second is the weaker uid-only control.

The status record's numbers were right and were distrusted, because the status record also — and correctly — said that the A–E mapping had not yet been recovered from the artefacts, and a table whose row labels are unknown invites the assumption that its values are unreliable too. They were not. The values used on this page are the primary-split values from answers.json, cross-checked against the layer-ranking parquet and the run's own report page.

None of this changes any conclusion. Corrected, D falls from 0.73 to 0.67 and B from 0.44 to 0.43; the ordering, the middle-of-the-stack finding, the C-against-B comparison and the steering result all stand unchanged. It is recorded because the alternative — quietly using the right numbers — would leave two of this project's own pages disagreeing with no explanation.

9. The steering vectors, and the geometry that shaped them

A probe direction is a vector in the 2,560-dimensional space of one tap. The vectors used here are difference-of-means directions rather than probe weights, which is the more common and more robust construction: take the mean activation of clips that are high on a dimension, subtract the mean of clips that are low, and the difference points from one to the other.

For each of 97 dimensions — the 40 emotion heads plus the 57 VoiceNet axes — and each of the 38 taps, three buckets are drawn: top1 (the top 1 % on the corpus percentile scale), bot1 (the bottom 1 %) and mid (the 5–10 % slice). From those, d_hi_lo, d_hi_mid and d_mid_lo.

One construction decision that had to be made, and what it cost

Within each bucket, rows are sorted by mean quality — the average of the genuineness and blend percentiles — and cut at 2,000. The reason is the main report's §13.1 finding: the most intense recordings are on average the least genuine, with median genuineness percentile falling from 0.391 in the top 10 % of a head to 0.360 in the top 1 %. Without the cut, an “intensity” direction would be substantially a “bad recording” direction.

The vector code states the price of the fix in the same breath, which is the right way to record a trade: mean(top1) − mean(bot1) is now a difference of two quality-matched extremes, not of two raw extremes. Something real was removed along with the confound.

Two further vectors exist for the same reason. A quality vector d_qual — the mean of the 2,000 highest-quality rows of the whole p3 extraction minus the mean of the 2,000 lowest — and an orthogonalised dimension vector d_dim_orth, which is d_hi_lo with its quality component projected out.

That orthogonalisation is not a formality. Measured:

Direction pairSigned cosineWhat it means
emotion d_hi_lo vs d_qual, at h20−0.75 Moving toward more of an emotion moves substantially away from higher measured quality.
emotion d_hi_lo vs d_qual, at loc−0.954 At the frame slot the two are very nearly anti-parallel.
VoiceNet d_hi_lo vs d_qual+0.46 The opposite sign: more of a VoiceNet axis goes with higher quality.

This is the §13.1 finding restated as geometry, and it is sharper inside the model than outside it. The corpus observation was a correlation between two scores. This is a cosine of −0.954 between two directions in the very last state before audio codes are chosen: at that point, in this model, “more emotional” and “more genuine” are close to opposite instructions. Any method that pushes on emotional intensity without controlling for it is pushing on quality in the wrong direction, and that includes every merge-weight sweep and every reward term in the main report. It is the strongest available argument for the quality gate that §13.1 imposes on training data, and it arrives from a completely different direction.

10. The steering grid: a clean negative result

The injection rule is

h  ←  h + α · (v / ‖v‖) · ‖h‖

so α is dimensionless: it is the fraction of the current hidden state's own magnitude added along the steering direction. α = 1 doubles the norm. Injection points are the taps themselves — tap 0 into the input embeddings, taps 1–35 by a forward hook on the corresponding layer, tap 36 into the last hidden state, and loc into the local transformer's state at the frame slot only, not the eleven within-frame channel steps. Steering is applied during generation only.

The grid is 393 clip records over 27 cells, each clip record being four sampled completions — 6 emotions × 2 languages × 4 samples per cell. Every clip is scored by the same instruments and the same harness as the rest of the project. The α = 0 control is shared across the grid and therefore carries 84 clip records rather than 12.

10.1 The α sweep on the dimension vector

αClip recordsWERDuration errorEmotion pctReward
−2.0120.99419.54 s0.40330.2347
−1.0121.07602.58 s0.48330.2245
−0.5121.06230.68 s0.39590.2286
0 (control)840.09410.01 s0.45790.4925
+0.5121.13940.27 s0.42180.2425
+1.0121.08221.27 s0.36170.2266
+2.0120.98877.66 s0.39090.2196

At every non-zero strength, in both directions, the output collapses. Unsteered, the model transcribes at word error rate 0.094 and lands within 0.01 s of the length its own script asks for. At α = +0.5 — the smallest positive strength tried — the word error rate is already 1.14, which means the recogniser produces more errors than there are words in the script. The composite reward halves at every non-zero cell and never recovers. The emotion percentile does not rise: it is 0.458 unsteered and lower at +0.5, +1.0 and +2.0.

10.2 The rest of the grid

CellVectorTapsαWERDuration errorEmotion pct
random controlrandh200.50.94850.00 s0.3686
random controlrandh201.02.06540.04 s0.3978
random controlrandh202.00.99569.59 s0.3410
quality-orthogonaldim_orthh20−1.01.18670.87 s0.2933
quality-orthogonaldim_orthh201.01.13613.73 s0.3327
quality-orthogonaldim_orthh202.01.07118.77 s0.2890
two tapsdimh20, h181.01.12054.80 s0.3943
three tapsdimh20, h18, h211.00.990011.54 s0.3020
four tapsdim+ h191.00.991511.16 s0.3938
five tapsdim+ h221.01.04956.14 s0.4810
early layerdimh061.00.997813.03 s0.4774
final normdimh361.01.15220.26 s0.3506
frame slotdimloc1.00.86261.32 s0.3746
quality vectorqualh22−1.01.10720.05 s0.2993
quality vectorqualh220.51.16202.99 s0.4957
quality vectorqualh221.01.033913.76 s0.5134
quality vectorqualh222.01.029713.76 s0.5482
quality, two tapsqualh22, h181.01.075413.76 s0.5120
quality, three tapsqual+ h231.00.990314.25 s0.5015
quality, five tapsqual+ h20, h241.00.996213.76 s0.5070

Tap order for the multi-tap stacks came from the ranking: the dimension vector follows Task B's layer ordering (h20, h18, h21, h19, h22) and the quality vector follows Task E's (h22, h18, h23, h20, h24). One cell (dim, five taps) lost one clip record to a generation failure and carries 11 rather than 12.

The row that would have been the headline, and why it is not

The quality vector at α = 2.0 reports the highest emotion percentile of the grid (0.548) and, in the reward's own terms, a perfect 1.000 on both genuineness and vocal-burst blend. Read alone, that is a spectacular success. Read with its neighbours it is the opposite: the same clips transcribe at word error rate 1.030 and are 13.76 seconds away from their requested duration. What is being scored is not better speech.

And the “1.000” is worse than it looks, because it is a percentile reward term, not a score. The raw values at that cell are genuineness 1.31 out of 6 and blend 1.97 out of 10 — near the bottom of both scales. The percentile mapping, built on a corpus of speech, has no idea what to do with audio that is not speech, and it maps it to the top. Every quality-vector cell in the table, at every α and every tap stack, reports exactly 1.000 on both terms. That constancy is the giveaway.

This is the sharpest instance in the whole project of a measurement instrument being confidently wrong, and it is precisely the failure the main report's §16 was written about. A steering result reported on quality scores alone, without word-error and duration controls alongside, would have been published as a win.

The random-vector control is what makes the result clean. A random Gaussian direction of matched magnitude at α = 1.0 gives word error rate 2.065 — roughly twice as damaging as the probe direction at the same strength — so the probe directions are not merely noise; they do less damage than chance. But at α = 0.5 the random direction gives 0.949 against the dimension vector's 1.139, i.e. it is less damaging there, and its emotion percentiles (0.34–0.40) sit inside the same range as the real directions. No cell of the grid shows the dimension vector moving its own attribute in a way a matched random vector does not. That is the result.

A superseded claim in the project's own protocol

The running protocol records an earlier reading of Phase 3 — “α = 1 at h20 raises emo_pct by +0.075, but a random direction of the same magnitude raises it by +0.135” — and correctly concludes from it that the causal claim is not established. Those two figures come from the smoke test, taken when the full grid was still queued: the aggregated artefacts under report/ hold one grid row and eight clips. The executed grid, run the following evening into steer/*.jsonl, gives α = 1 at h20 an emotion percentile of 0.362 against the control's 0.458 — a fall, not a rise — and the random direction 0.398, also below control. The conclusion is unchanged and is if anything stronger; only the supporting numbers move. The grid was never re-aggregated into the report artefacts, so anything reading report/steer_grid.parquet is still reading the smoke test. The tables above are aggregated from the raw per-clip records.

11. Reading the steering failure

Four readings are consistent with the grid. They are not mutually exclusive and none is tested yet.

  1. The intervention is in the wrong place. The vectors are differences of means over a window average — a summary that exists nowhere in the model as a single activation. Adding it at one tap at every generated frame is not the inverse of the operation that produced it. A direction found by averaging is not necessarily a direction the model can be pushed along.
  2. The regimes do not match. The directions were extracted teacher-forced, with real audio on the assistant side, and are injected while the model generates freely. That is the gap the extraction code warns about, and this grid is the measurement of how large it is. The probes say an attribute is decodable while the model follows a recording; the steering says the model cannot be driven along that direction while it generates.
  3. The output space is brittle in a way a text model's is not. The target is discrete residual-vector-quantised audio codes across 13 channels. A perturbation that would leave a text model producing odd but well-formed sentences leaves this one producing codes that decode to something a recogniser cannot read. The collapse appearing already at α = 0.5 — small by the standards of the text-steering literature — is consistent with that, as is the fact that h36, the very last state, is one of the most damaging injection points (WER 1.152) despite having the least network left to propagate through.
  4. The dimension direction may be mostly a quality direction. §9 measured cos(d_hi_lo, d_qual) = −0.75 at h20 for emotion heads. Adding an emotion direction is therefore substantially subtracting a quality direction, which is one concrete mechanism for the degradation. The orthogonalised vector was built to test exactly this — and it degrades the output too, at every α, so if this is part of the story it is not the whole of it.

Reading 1 is the cheapest to test; reading 3 is the most likely to be decisive. The practical conclusion for this project is narrower and firmer than any of them: activation steering is not currently a route to intensity control here, and the budget that would have gone into tuning it is better spent on the data-side levers the main report identifies.

12. What would be worth trying next

  1. Run Task A2 and write its numbers out. It already exists in the code. It turns Task A from an under-specified question into a specified one, and the difference between A and A2 is a direct measurement of what conditioning is worth — the same quantity the entire intensity problem turns on.
  2. Pull the h36 retention figure for C, D and E. The 39 % emotion loss into the decoder is the most suggestive single number here, and the layer ranking already contains everything needed to say whether the other four attributes survive the same journey better. It costs no GPU time.
  3. Sweep below α = 0.5. The grid's smallest non-zero strength already produces a word error rate above 1.0. Whether there is a usable window between 0 and 0.5 or the collapse is immediate is unknown and costs one afternoon.
  4. Probe the generating model, not the teacher-forced one. Extract activations from free generation and ask whether the same attributes are decodable there. If they are not, that is a more interesting negative result than this one and it would explain the steering failure outright.
  5. Use the pairs extraction. 53,325 rows were captured from the preference corpus specifically so that a chosen-minus-rejected contrast direction could be built. That direction is not in the grid above.
  6. Re-aggregate the grid into the report artefacts, so that report/steer_grid.parquet stops describing a smoke test.

13. Provenance, artefacts and limits

Base modelout/sft3/export — published as …-v2-sft3
Adapter (stacked, never merged)out/dpo_sft3_p2/ckpt-step5022/adapter — published as laion/moss-va-sft3-dpo-lora-p2
Shape36 layers, hidden 2,560; 38 taps per row
Capture windowfrom 80 % through the assistant audio span to its end, capped at 100 frames, floored at 8
Extraction / consolidationactf_extract.py, actf_consolidate.py
Task definitionsactf_probe.py::build_targets
Vector constructionactf_vectors.py; vectors at vectors/p3_vectors.npz (97 dimensions × 38 taps × 2,560, plus the quality vector and diagnostics)
Injectionactf_steer.py; executed grid plan grids/prio_all.json (27 cells)
Probe resultsreport/answers.json, layer_ranking.parquet (1,160 rows = 390 main/voice + 380 main/uid + 390 neutral/voice, where each 380 is 2 models × 5 tasks × 38 taps and each 390 adds 10 baseline rows)
Steering resultssteer/*.jsonl, 393 clip records over 27 cells. The aggregated report/steer_grid.parquet is the earlier smoke test and should not be read.
Activation taps on disk75.5 GB, float16, tap-major, out/actforensics/taps/not published. They encode the source corpus, and whether teacher-forced activations of non-public recordings can be released, and under what licence, is unresolved.
Probe weights and steering vectors254 MB, out/actforensics/{vectors,probe,probe2}/ — small and publishable

13.1 Limits of everything above


Part of the MOSS voice-acting documentation set: the technical report · the trajectory corpus. Every number on this page was read from a named on-disk artefact; where two of this project's own records disagreed, §8 and §10 show both and say which is right and why.