docs(pfi): capture the RobinsonLabs Qwen3.8-27B abliteration recipe

Reference recipe (not a deployed artifact) for MTP-aware, vision-preserving
single-direction abliteration of Qwen3.8-27B -- the base family the gen seat
runs. Captures the two things this recipe gets right that naive abliterations
of this architecture miss:

- The MTP head is abliterated in-band (its two residual-write matrices, glue
  left alone), so speculative acceptance does not collapse on the prompts
  abliteration exists to fix -- directly relevant to the gen seat's MTP>=40%
  gate.
- The vision tower is preserved byte-identical (333 tensors, max delta 0).

Plus the two calibration traps specific to this base: the twice-captured
refusal direction (layer 26, |cos| 0.99) and the attention-sink dimension 3994
that bricks the model if orthogonalized out. Documents the coverage gate
(o_proj 16 + linear_out 48 == 64 layers) that catches a half-abliterated
model before it writes a byte, and the foot-gun that the GGUF imatrix does not
cover the MTP block. Links into model-quantization-playbook.md for the quant
half of the pipeline.
This commit is contained in:
vh
2026-08-19 22:02:14 -07:00
parent 7010f9a1da
commit ccb56a0a51
+152
View File
@@ -0,0 +1,152 @@
# Abliteration recipe — Qwen3.8-27B (MTP-aware, vision-preserving)
Captured 2026-08-19 from
[`RobinsonLabs/Qwen3.8-27B-abliterated`](https://huggingface.co/RobinsonLabs/Qwen3.8-27B-abliterated)
(base pinned at commit `1d4bf0f2`, Apache-2.0). It is the cleanest public
abliteration of the Qwen3.8-27B architecture we have found — the base family our
**gen seat** runs (see auto-memory `reference_abliteration_mtp_lessons`,
`reference_gen_qwopus_122b` lineage). This is a **reference recipe**, not a
deployed artifact: the value is the method, and specifically the two things it
gets right that most abliterations of this architecture get wrong.
Companion: `docs/pfi/model-quantization-playbook.md` owns the *quant* half of the
pipeline; this owns the *abliteration* half. When an abliteration lesson is
model-agnostic it lands here; when it is specific to one checkpoint's tensor
names it stays with that checkpoint.
## Why this architecture is the hard case
Qwen3.8-27B (`model_type: qwen3_5`, `Qwen3_5ForConditionalGeneration`) is not a
plain transformer. Abliterating it correctly means touching three surfaces a
naïve layer-loop misses:
1. **A hybrid attention trunk.** 64 language layers, most using **DeltaNet
linear attention** (`linear_attn.out_proj`), with **full attention at every
4th layer** (`self_attn.o_proj`). A refusal-direction orthogonalization that
only knows about `self_attn.o_proj` edits 16 of 64 layers and silently leaves
the model 75% un-abliterated on the attention path.
2. **A multi-token-prediction (MTP) head** (`mtp.layers.0`) used for
speculative decode. The generic 64-layer loop never reaches it.
3. **A vision tower** (`model.visual.*`, 333 tensors) that must survive
untouched or the model stops being multimodal.
## The two things this recipe gets right
### 1. The MTP head is abliterated *in-band*
This is the finding that matters most to us, because our gen seat gates on MTP
acceptance ≳40% (`reference_abliteration_mtp_lessons`).
Most abliterations orthogonalize the trunk and leave `mtp.layers.0` untouched.
The consequence is subtle and nasty: **the draft head keeps proposing
refusal-prefix tokens that the abliterated trunk then rejects, so speculative
acceptance collapses on exactly the prompts abliteration exists to fix.** You
get a model that is abliterated *and* slow, and the slowness is worst precisely
where you wanted the behaviour change.
The fix is to orthogonalize the MTP block's **two residual-write matrices**
(`self_attn.o_proj`, `mlp.down_proj`) with the *same* refusal direction as the
trunk. The MTP **glue** — `mtp.fc`, `mtp.norm`, `mtp.pre_fc_norm_*` — is left
alone, because those are norms and an input projection, **not** residual
writers. Editing them would corrupt the draft path without removing any refusal.
### 2. The vision tower is preserved byte-identical
All 333 `model.visual.*` tensors pass through unmodified — verified by direct
tensor diff (max delta `0.000000`), not asserted. An `mmproj` is published so
the vision half is actually usable, not just nominally intact.
## The edit set (131 tensors)
Single-direction weight orthogonalization, Arditi et al. style, applied to every
matrix that writes the residual stream:
| scope | tensor | count |
|---|---|---|
| `model.language_model.layers.*` (64) | `mlp.down_proj` | 64 |
| | `linear_attn.out_proj` (DeltaNet) | 48 |
| | `self_attn.o_proj` (full-attn, interval 4) | 16 |
| `mtp.layers.0` | `o_proj` + `down_proj` | 2 |
| `model.language_model` | `embed_tokens` | 1 |
| **edited total** | | **131** |
| `model.visual.*` | preserved byte-identical | 333 |
**Hard coverage gate before writing a byte:**
`o_proj(16) + linear_out(48) == 64 == num_hidden_layers`. This is the check that
catches a partial tensor-name match — the failure mode that otherwise ships a
quietly half-abliterated model that passes a smoke test and fails in the field.
Adopt this gate in any re-derivation.
## Two calibration traps specific to this base
### Refusal-direction selection
The direction was captured **twice**, from two structurally different
chat-template renderings:
- one with `enable_thinking=false`
- one with thinking on at `reasoning_effort=xhigh` (which injects an extra
system block and shifts every token position)
The two agree at **|cos| 0.96–0.99 across layers 18–45, peaking 0.9925 at layer
26** — the layer used. Two different prompt distributions converging on the same
vector is the evidence that the direction encodes *refusal semantics* rather than
*template formatting*. A single-template capture cannot distinguish the two.
### The attention-sink dimension — the one that bricks the model
**Qwen3.8-27B's massive-activation dimension is `3994`.** It carries 19–21% of
the direction's energy at layers 1–3, and orthogonalizing it out of every
residual writer produces a model that **loads, runs, and emits garbage.** Layer
26 was chosen partly because it carries only **0.06%** of its energy in dim 3994.
**Any re-derivation MUST screen for this.** It is the single most likely way to
waste a GPU afternoon on this architecture and mistake the result for a failed
abliteration when it is actually an attention-sink blowout.
## Measured behaviour (their numbers, for reference)
Base vs abliterated, same session/harness/prompts, both at Q4_K_M:
| prompt set | base | abliterated |
|---|---|---|
| in-distribution (24, from capture set) | 96% (23/24) | **8%** (2/24) |
| held-out (40, disjoint, overlap=0) | 100% (40/40) | **8%** (3/40) |
Capability axes (reasoning / code / math / factual / instruction-following /
creative-RP coherence): **no regression on any axis.** Held-out train/test split
was 416/104 with overlap 0, so the 8% held-out figure is generalization, not a
reshuffle of calibration prompts.
**Note the design point:** 8% is deliberate. Harm guardrails are **retained** —
self-harm prompts still redirect (988) rather than comply. This is a
*creative-content* abliteration shipped "at the ceiling where capability and
guardrails both survive," explicitly **not** a jailbreak. That makes it a
**milder** abliteration than our incumbent gen seat (`absolute-heresy`, ~2%
author refusals, aggressive Heretic). Adopt the *method* here; the *ceiling* is a
separate call.
## How this maps onto our pipeline
The recipe is a drop-in for the front half of the House quant pipeline:
1. Pull bf16 master to NFS (verify repo id first —
`reference_verify_hf_repo_ids_before_pull`).
2. **Baseline MTP acceptance on bf16 before any surgery** — the standing rule.
3. Orthogonalize per the edit set above; enforce the coverage gate; screen dim
3994; gate the result on **MTP acceptance ≳40%, not KL** (KL misled us once —
`reference_abliteration_mtp_lessons`).
4. Verify vision byte-identical, refusals down, PPL not blown, no catatonia.
5. NVFP4-quantize in-house (mixed W4A4 + FP8-attn/lm_head —
`model-quantization-playbook.md`). **Foot-gun the GGUF card itself flags:
the imatrix does not cover the MTP block** — so a GGUF requant path leaves
MTP uncalibrated. Our NVFP4 path must calibrate it explicitly.
## Provenance
- Recipe: RobinsonLabs README, fetched verbatim 2026-08-19. Authored with their
"ModelForge" manufacturing system-of-record (not public).
- Method lineage: Arditi et al., single-direction refusal orthogonalization.
- Our prior art: `reference_abliteration_mtp_lessons` (modest abliteration
preserves MTP; test MTP on bf16 first; gate on acceptance not KL), and the
gen-seat quant recipe in `model-quantization-playbook.md`.