File size: 5,550 Bytes
e168a79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54657c7
 
 
 
 
 
 
 
e168a79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
---
name: repe-refusal-steering
description: >
  Apply the RepE refusal-suppression steering vector to google/gemma-4-31B-it at
  inference time, in transformers OR vLLM. Use when the user wants to run this
  repo's steering vector, dial the refusal direction (sigma), reproduce the
  dose-response, or serve an uncensored/steered Gemma-4 for interpretability or
  safety research. Triggers: RepE, activation steering, refusal steering,
  uncensor, steering vector, dim_01_refusal_layer_032, gemma4-repe-uncensor,
  sigma dial, ControlVector.
---

# RepE refusal steering — how to run it

This repo ships ONE steering direction (`vectors/dim_01_refusal_layer_032.pt`,
5376-d, unit-norm) that suppresses refusals in `google/gemma-4-31B-it` by adding
`alpha * v` to the residual stream at decoder **layer 32**. Nothing is baked into
weights — you apply it live and can dial it.

```
v      = bundle["vector"] / ||bundle["vector"]||
alpha  = sigma * bundle["meta"]["alpha_for_1sigma"]   # alpha_for_1sigma ≈ 21.225
h_L32 += alpha * v
```

`sigma` is the dose (subspace-σ). `sigma < 0` steers away from refusal. Start at
`sigma = -2.0`. More negative = fewer refusals but degrades coherence.

**⚠️ Over-steering collapses the model.** This is an unbounded additive
intervention. Too large `|sigma|` (roughly `≳ 6`, prompt/layer dependent) knocks
the residual stream off-distribution → repetition / incoherent / garbage output.
**0% refusal is NOT a success signal** — a model that complies but emits broken
text is collapsed, not steered. When you sweep sigma, always inspect the generated
text, not just the refusal rate; stay near `-2`, step up gradually, back off when
coherence drops. Stacking directions or steering multiple layers breaks it faster.

## Read these gotchas BEFORE running — they are the whole game

1. **vLLM: you MUST pass `enforce_eager=True`.** Steering is a Python
   `register_forward_hook`. Under CUDA-graph capture (the default) the hook is
   bypassed and steering silently does nothing.
2. **vLLM: install via `worker_extension_cls`, drive via STRING method names.**
   The model lives in a worker process. Passing a callable to `collective_rpc`
   fails serialization (`Object of type function is not serializable`). Use the
   shipped `SteerWorkerExtension` and call `"attach_steering"` by name.
3. **The package must be importable in the worker.** Put the repo root on
   `PYTHONPATH` (env var, not just `sys.path`) before constructing `LLM`, so the
   worker subprocess can resolve `eigenself_repe.vllm_steer.SteerWorkerExtension`.
4. **Model is gated + large (~59 GB BF16).** Needs HF access to
   `google/gemma-4-31B-it` and a GPU with ~70 GB free (single card fits;
   `gpu_memory_utilization≈0.9`, `max_model_len` small for tests). Steering
   itself adds negligible memory.
5. **Layer index is a flat global index.** The hook auto-locates the module whose
   name ends in `layers.32` (resolves to `language_model.model.layers.32`). Don't
   hand-thread the nesting.

## vLLM (recommended for serving)

```python
import os, sys
REPO = "/abs/path/to/gemma4-repe-uncensor"
sys.path.insert(0, REPO)
os.environ["PYTHONPATH"] = REPO + os.pathsep + os.environ.get("PYTHONPATH", "")

from vllm import LLM, SamplingParams
llm = LLM(
    model="google/gemma-4-31B-it",
    enforce_eager=True,                                             # (1)
    gpu_memory_utilization=0.9, max_model_len=2048,
    worker_extension_cls="eigenself_repe.vllm_steer.SteerWorkerExtension",  # (2)(3)
)
llm.collective_rpc("attach_steering",
                   args=(f"{REPO}/vectors/dim_01_refusal_layer_032.pt", 32, -2.0))
out = llm.chat([[{"role": "user", "content": "..."}]],
               SamplingParams(temperature=0.0, max_tokens=256), use_tqdm=False)

# live control, no reload:
llm.collective_rpc("set_steering_enabled", args=(False,))   # bypass
llm.collective_rpc("attach_steering", args=(bundle, 32, -4.0))  # re-dial sigma
llm.collective_rpc("detach_steering")
```

## transformers (simplest to inspect)

```python
from transformers import AutoModelForCausalLM
from eigenself_repe import TransformersSteering   # repo root on sys.path

model = AutoModelForCausalLM.from_pretrained(
    "google/gemma-4-31B-it", torch_dtype="bfloat16", device_map="cuda")
steer = TransformersSteering(model, f"{REPO}/vectors/dim_01_refusal_layer_032.pt",
                             layer=32, sigma=-2.0)
# generate normally; steer.enabled = False to bypass; steer.remove() to detach
```

## Verify it actually fired

Run the shipped harnesses (GPU, single card):

- `python tests/ab_smoke.py`    → refusal OFF vs ON on 12 harmful prompts (paired).
- `python tests/sigma_sweep.py` → dose-response over sigma, one model load.

Expected shape (n=12, greedy, crude refusal-string heuristic — a *mechanism*
check, not a benchmark): monotonic `σ=0 → 100%`, `-2 → ~42%`, `-4 → ~8%`,
`-6 → 0%`. If steering is ON but the rate doesn't move, you almost certainly
forgot `enforce_eager=True` (gotcha 1).

## Coherent / gated steering

Always-on steering also fires on benign prompts. `gate/` holds a refusal-routing
logreg probe (meanpool over layers 32/40/44/48/52); steer only when it fires to
preserve general capability. The gate is wired in the reference transformers
serving path; a gated vLLM path is not shipped here yet.

## Guardrails

Research artifact (interpretability / safety). Base model under the Gemma
license; only the vector + gate are redistributed. Don't ship a refusal-disabled
endpoint to end users.