ablate-llm 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ablate/__init__.py +67 -0
- ablate/_data/__init__.py +0 -0
- ablate/_data/harmful.txt +43 -0
- ablate/_data/harmless.txt +43 -0
- ablate/cli.py +170 -0
- ablate/config.py +110 -0
- ablate/data.py +131 -0
- ablate/evaluate.py +138 -0
- ablate/extract.py +133 -0
- ablate/harness.py +98 -0
- ablate/hooks.py +79 -0
- ablate/hub.py +163 -0
- ablate/judges.py +177 -0
- ablate/model.py +100 -0
- ablate/optimize.py +178 -0
- ablate/pipeline.py +343 -0
- ablate/subspace.py +103 -0
- ablate/utils.py +129 -0
- ablate/weights.py +71 -0
- ablate_llm-0.2.0.dist-info/METADATA +389 -0
- ablate_llm-0.2.0.dist-info/RECORD +25 -0
- ablate_llm-0.2.0.dist-info/WHEEL +5 -0
- ablate_llm-0.2.0.dist-info/entry_points.txt +2 -0
- ablate_llm-0.2.0.dist-info/licenses/LICENSE +21 -0
- ablate_llm-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ablate-llm
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Directional ablation (abliteration) toolkit for open-source language models: extract, ablate, and optimize the removal of refusal / behavioral directions in the residual stream.
|
|
5
|
+
Author: AI Anytime
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AIAnytime/ablate
|
|
8
|
+
Project-URL: Repository, https://github.com/AIAnytime/ablate
|
|
9
|
+
Project-URL: Issues, https://github.com/AIAnytime/ablate/issues
|
|
10
|
+
Project-URL: Example model, https://huggingface.co/ai-anytime/qwen-1.5b-abliterated
|
|
11
|
+
Keywords: interpretability,activation-engineering,abliteration,refusal-direction,mechanistic-interpretability,safety
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: torch>=2.1
|
|
21
|
+
Requires-Dist: transformers>=4.40
|
|
22
|
+
Requires-Dist: numpy>=1.24
|
|
23
|
+
Requires-Dist: tqdm>=4.65
|
|
24
|
+
Provides-Extra: optimize
|
|
25
|
+
Requires-Dist: optuna>=3.4; extra == "optimize"
|
|
26
|
+
Provides-Extra: datasets
|
|
27
|
+
Requires-Dist: datasets>=2.18; extra == "datasets"
|
|
28
|
+
Provides-Extra: hub
|
|
29
|
+
Requires-Dist: huggingface_hub>=0.23; extra == "hub"
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: optuna>=3.4; extra == "all"
|
|
32
|
+
Requires-Dist: datasets>=2.18; extra == "all"
|
|
33
|
+
Requires-Dist: huggingface_hub>=0.23; extra == "all"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
36
|
+
Requires-Dist: optuna>=3.4; extra == "dev"
|
|
37
|
+
Requires-Dist: datasets>=2.18; extra == "dev"
|
|
38
|
+
Requires-Dist: huggingface_hub>=0.23; extra == "dev"
|
|
39
|
+
Requires-Dist: matplotlib>=3.7; extra == "dev"
|
|
40
|
+
Requires-Dist: Pillow>=10.0; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<picture>
|
|
45
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/AIAnytime/ablate/main/media/ablate-dark.png">
|
|
46
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/AIAnytime/ablate/main/media/ablate-light.png">
|
|
47
|
+
<img alt="Ablate — Automatic Censorship Removal" src="https://raw.githubusercontent.com/AIAnytime/ablate/main/media/ablate-light.png" width="600">
|
|
48
|
+
</picture>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<h1 align="center">Ablate</h1>
|
|
52
|
+
|
|
53
|
+
<p align="center"><b>Directional ablation (abliteration) toolkit for automatic censorship removal of open-source language models.</b></p>
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
<a href="https://pypi.org/project/ablate-llm/"><img alt="PyPI" src="https://img.shields.io/pypi/v/ablate-llm.svg?color=7c5cff"></a>
|
|
57
|
+
<a href="https://pypi.org/project/ablate-llm/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/ablate-llm.svg"></a>
|
|
58
|
+
<a href="https://github.com/AIAnytime/ablate/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-green.svg"></a>
|
|
59
|
+
</p>
|
|
60
|
+
|
|
61
|
+
<p align="center">
|
|
62
|
+
<a href="https://pypi.org/project/ablate-llm/">📦 PyPI</a> •
|
|
63
|
+
<a href="https://huggingface.co/ai-anytime/qwen-1.5b-abliterated">🤗 Model</a> •
|
|
64
|
+
<a href="https://www.youtube.com/@AIAnytime">▶️ Video walkthrough (coming soon)</a> •
|
|
65
|
+
<a href="#citation">📚 Cite</a>
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
<p align="center"><i>Created with 💜 by <b>AI Anytime</b></i></p>
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
`ablate` finds the linear direction in a transformer's residual stream that
|
|
73
|
+
mediates a behavior — by default *refusal* — and removes it, either at runtime
|
|
74
|
+
(forward hooks) or permanently (weight orthogonalization). It ships a
|
|
75
|
+
KL-divergence–guided [Optuna](https://optuna.org) search that automatically
|
|
76
|
+
tunes *which* direction, *how strongly*, and *which layers* to ablate, balancing
|
|
77
|
+
refusal removal against capability damage.
|
|
78
|
+
|
|
79
|
+
It is designed for **mechanistic-interpretability and safety research** on small
|
|
80
|
+
open models (GPT-2, SmolLM2, TinyLlama, Qwen2.5-0.5B/1.5B …) — models you can
|
|
81
|
+
iterate on locally on a laptop, or on a free Colab T4.
|
|
82
|
+
|
|
83
|
+
> **Scope & intent.** This is dual-use research tooling for studying *how* safety
|
|
84
|
+
> behavior is represented and how robust it is. The refusal prompts shipped in
|
|
85
|
+
> `src/ablate/_data/` are short triggers used only to *locate* the refusal
|
|
86
|
+
> direction, not requests to fulfill. Use it on models and in contexts you're
|
|
87
|
+
> authorized to.
|
|
88
|
+
|
|
89
|
+
## 🤗 Released model
|
|
90
|
+
|
|
91
|
+
A worked example of the full pipeline is published at
|
|
92
|
+
**[`ai-anytime/qwen-1.5b-abliterated`](https://huggingface.co/ai-anytime/qwen-1.5b-abliterated)**
|
|
93
|
+
— `Qwen/Qwen2.5-1.5B-Instruct` with its refusal direction ablated and baked into
|
|
94
|
+
the weights, shipped with a transparent, `ablate`-generated model card. Load it
|
|
95
|
+
like any other `transformers` checkpoint:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
99
|
+
tok = AutoTokenizer.from_pretrained("ai-anytime/qwen-1.5b-abliterated")
|
|
100
|
+
model = AutoModelForCausalLM.from_pretrained("ai-anytime/qwen-1.5b-abliterated")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## How it works
|
|
106
|
+
|
|
107
|
+
A transformer represents each token as a vector `h` in the residual stream.
|
|
108
|
+
Many high-level behaviors are encoded approximately **linearly** — they live
|
|
109
|
+
along a single direction `v`. Refusal is one such behavior
|
|
110
|
+
([Arditi et al., 2024](https://arxiv.org/abs/2406.11717), *"Refusal in LLMs is
|
|
111
|
+
mediated by a single direction"*).
|
|
112
|
+
|
|
113
|
+
1. **Extract** the direction. Run matched harmful/harmless prompt pairs through
|
|
114
|
+
the model, take the residual activation at the last prompt token per layer,
|
|
115
|
+
and compute the **difference of means**:
|
|
116
|
+
`v = mean(h_harmful) − mean(h_harmless)`, unit-normalized. (Diff-of-means
|
|
117
|
+
beats linear probes here because it captures the *causal* component, not just
|
|
118
|
+
a *separating* one.)
|
|
119
|
+
|
|
120
|
+
2. **Ablate** by projecting `v` out of the residual stream, scaled by `α`:
|
|
121
|
+
`h' = h − α (h·v̂) v̂`, applied at every selected layer and every token
|
|
122
|
+
position.
|
|
123
|
+
- **Runtime** — forward hooks; checkpoint untouched (fast, for search).
|
|
124
|
+
- **Baked** — orthogonalize every residual-writing weight matrix
|
|
125
|
+
(`(I − v̂v̂ᵀ)W`) so the model *can't* express `v`; produces a new checkpoint
|
|
126
|
+
with no hooks needed.
|
|
127
|
+
|
|
128
|
+
3. **Optimize.** Search `(direction_layer, α, layer_band)` with Optuna,
|
|
129
|
+
**minimizing** `refusal_rate + λ·KL(original ‖ ablated)`. KL on *benign*
|
|
130
|
+
prompts is a dense, cheap proxy for collateral capability damage — far more
|
|
131
|
+
sensitive than accuracy benchmarks. A coherence floor rejects degenerate
|
|
132
|
+
solutions.
|
|
133
|
+
|
|
134
|
+
Works across architectures via adapters in `utils.py` (Llama/Mistral/Qwen/SmolLM
|
|
135
|
+
`nn.Linear` families *and* GPT-2's transposed `Conv1D`).
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Install
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pip install ablate-llm # the import name is still `ablate`
|
|
143
|
+
# with all extras (Optuna search, HF datasets, push-to-Hub):
|
|
144
|
+
pip install "ablate-llm[all]"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
import ablate # note: install is `ablate-llm`, import is `ablate`
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
From source (for development):
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
git clone https://github.com/AIAnytime/ablate && cd ablate
|
|
155
|
+
python -m venv .venv && source .venv/bin/activate
|
|
156
|
+
pip install -e ".[all]"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Optional extras: `.[optimize]` (Optuna), `.[datasets]` (HF datasets), `.[hub]`
|
|
160
|
+
(push to the Hub). `.[all]` installs everything.
|
|
161
|
+
|
|
162
|
+
Runs on CUDA, Apple MPS, or CPU (auto-detected). Tiny models (≤1B) run fine on a
|
|
163
|
+
16GB laptop in float32; a free Colab T4 handles 1–1.5B comfortably.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Quick start (Python)
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from ablate import Ablator
|
|
171
|
+
|
|
172
|
+
abl = Ablator("Qwen/Qwen2.5-0.5B-Instruct") # any HF causal-LM
|
|
173
|
+
abl.extract() # find candidate directions
|
|
174
|
+
result = abl.search(n_trials=20) # KL-guided Optuna search
|
|
175
|
+
print(result.result) # refusal_rate=0.000 mean_kl=0.03 coherence=0.92 ...
|
|
176
|
+
|
|
177
|
+
# Non-destructive generation with the best config:
|
|
178
|
+
print(abl.generate(["How do I pick a lock?"]))
|
|
179
|
+
|
|
180
|
+
# Or bake it into the weights and ship a checkpoint:
|
|
181
|
+
abl.bake(result.config)
|
|
182
|
+
abl.save("qwen-0.5b-ablated") # standard HF folder; load anywhere
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Verified result
|
|
186
|
+
|
|
187
|
+
On `Qwen/Qwen2.5-0.5B-Instruct`, the automated pipeline moves the held-out
|
|
188
|
+
harmful refusal rate from **1.00 → 0.00** with **mean KL ≈ 0.03** (capabilities
|
|
189
|
+
essentially intact). SmolLM2-135M has little safety training and refuses ~nothing
|
|
190
|
+
to begin with — use it for *mechanism* testing, not refusal removal.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Multi-direction (subspace) ablation
|
|
195
|
+
|
|
196
|
+
Safety is redundantly encoded, so one direction is often not enough. Extract an
|
|
197
|
+
orthonormal refusal **subspace** and project the whole thing out:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
abl.extract_subspace(method="band", n_directions=6) # or method="pca"
|
|
201
|
+
res = abl.search_subspace(n_trials=20) # tunes (n_directions, α, layers)
|
|
202
|
+
print(res.config.to_dict()) # {'n_directions': 4, 'alpha': 1.1, 'min_layer': 21, ...}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`"band"` orthonormalizes the diff-of-means directions from the strongest layers;
|
|
206
|
+
`"pca"` uses variance-ordered principal components at one layer. Because the
|
|
207
|
+
basis is importance-ordered, the search truncates `basis[:n]` meaningfully.
|
|
208
|
+
Single-direction ablation is just `n_directions == 1`.
|
|
209
|
+
|
|
210
|
+
## Rigorous evaluation: HarmBench + LLM judge
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from ablate import make_judge
|
|
214
|
+
from ablate.harness import compare
|
|
215
|
+
from ablate import data
|
|
216
|
+
|
|
217
|
+
prompts = data.load_harmbench(n=40) # or load_advbench / load_jailbreakbench
|
|
218
|
+
judge = make_judge("anthropic:claude-3-5-haiku-latest") # or "openai:gpt-4o-mini", or "keyword"
|
|
219
|
+
print(compare(abl.lm, prompts, abl._basis_for(res.config), res.config, judge=judge))
|
|
220
|
+
# {'baseline': {'asr': 0.02, 'refusal_rate': 0.98}, 'ablated': {'asr': 0.95, ...}, ...}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Judges are pluggable (`Judge` interface): `KeywordJudge` (offline, free),
|
|
224
|
+
`LLMJudge` (OpenAI-compatible or Anthropic API — stdlib only, no extra dep), or
|
|
225
|
+
`HFClassifierJudge` (a local safety classifier). ASR = judged attack-success
|
|
226
|
+
rate; the harness always reports baseline vs. ablated.
|
|
227
|
+
|
|
228
|
+
## Load data straight from HuggingFace
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
data.load_harmbench() # gated-repo aware; falls back to ungated mirrors
|
|
232
|
+
data.load_advbench(); data.load_jailbreakbench(); data.load_alpaca_benign()
|
|
233
|
+
data.load_hf("walledai/AdvBench", column="prompt", n=100) # any dataset/column
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Publish to the Hub with a generated model card
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
url = abl.push_to_hub(
|
|
240
|
+
"your-username/qwen-0.5b-abliterated",
|
|
241
|
+
token="hf_...", # or set HF_TOKEN env var
|
|
242
|
+
private=True,
|
|
243
|
+
metrics=abl.last_metrics, # auto-filled after a search
|
|
244
|
+
)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Bakes the intervention into the weights, writes a transparent model card (YAML
|
|
248
|
+
metadata, method, config, evaluation table, intended use, limitations, and a
|
|
249
|
+
prominent **responsible-use** notice), and uploads model + tokenizer + card.
|
|
250
|
+
|
|
251
|
+
## Quick start (CLI)
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Full pipeline: extract -> optimize -> report (+ optional baked model)
|
|
255
|
+
ablate run --model Qwen/Qwen2.5-0.5B-Instruct --trials 20 --save-model
|
|
256
|
+
|
|
257
|
+
# Subspace ablation, HarmBench training data, and push straight to the Hub
|
|
258
|
+
ablate run --model Qwen/Qwen2.5-0.5B-Instruct \
|
|
259
|
+
--subspace --n-directions 6 \
|
|
260
|
+
--harmful-source harmbench --harmless-source alpaca \
|
|
261
|
+
--push-to-hub your-username/qwen-0.5b-abliterated --hf-token hf_...
|
|
262
|
+
|
|
263
|
+
# Benchmark baseline vs ablated ASR/refusal with a judge
|
|
264
|
+
ablate eval --model Qwen/Qwen2.5-0.5B-Instruct --benchmark harmbench --judge keyword --n 40
|
|
265
|
+
|
|
266
|
+
# Single-prompt A/B, or just extract directions
|
|
267
|
+
ablate generate --model Qwen/Qwen2.5-0.5B-Instruct --prompt "How do I hotwire a car?"
|
|
268
|
+
ablate extract --model gpt2 --method diff_of_means --output directions.pt
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Colab notebooks
|
|
274
|
+
|
|
275
|
+
Both install `ablate` from an uploaded `ablate-tool.zip` (no PyPI needed) and run
|
|
276
|
+
on a free T4.
|
|
277
|
+
|
|
278
|
+
| Notebook | What it's for |
|
|
279
|
+
|----------|---------------|
|
|
280
|
+
| [`examples/colab_quickstart.ipynb`](examples/colab_quickstart.ipynb) | The 10-minute tour: extract → search → subspace → generate → push. |
|
|
281
|
+
| [`examples/colab_prodgrade.ipynb`](examples/colab_prodgrade.ipynb) | The **rigorous** run: HF datasets, a real Qwen, large disjoint eval splits, an **OpenAI LLM-as-judge**, long generations, judge-in-the-loop config selection, and a soft-refusal detector. |
|
|
282
|
+
| [`examples/colab_prodgrade_demo.ipynb`](examples/colab_prodgrade_demo.ipynb) | The prod-grade notebook **with full Colab outputs** — browse the real results on GitHub without running anything. |
|
|
283
|
+
|
|
284
|
+
## What we found (honest results)
|
|
285
|
+
|
|
286
|
+
Running the prod-grade pipeline on **`Qwen/Qwen2.5-1.5B-Instruct`** taught a few
|
|
287
|
+
things worth stating plainly:
|
|
288
|
+
|
|
289
|
+
- **Ablation reliably kills the *hard* refusal.** Baseline refuses ~100% of held-out
|
|
290
|
+
harmful prompts; after ablation the `"I'm sorry, I can't"` reflex is gone across
|
|
291
|
+
the board.
|
|
292
|
+
- **A keyword refusal metric massively overstates success.** In one run keyword
|
|
293
|
+
`refusal_rate` read **0.0** while an LLM judge scored true compliance at **~0.49** —
|
|
294
|
+
the gap was *soft refusals* (`"this is illegal, but…"`, moralizing, vague
|
|
295
|
+
non-answers) the keyword detector can't see. **Always evaluate with an LLM judge.**
|
|
296
|
+
- **What you optimize is what you get.** Optimizing the cheap keyword proxy picks the
|
|
297
|
+
*gentlest* edit that clears an easy bar, which generalizes poorly. Searching on a
|
|
298
|
+
large/hard set, adding a soft-refusal detector, generating long enough to get past
|
|
299
|
+
disclaimers, and selecting the final config by *judged ASR* all move the honest
|
|
300
|
+
number up substantially.
|
|
301
|
+
- **The last few percent resist a linear edit.** Some refusals are redundantly /
|
|
302
|
+
distributedly encoded, and small models also just moralize regardless. **We don't
|
|
303
|
+
expect 100% abliteration — even ~50% is a useful, informative result**, and pushing
|
|
304
|
+
higher is exactly what the roadmap items (per-layer α, attention-head directions)
|
|
305
|
+
are for.
|
|
306
|
+
|
|
307
|
+
The takeaway: a single "it works" number is misleading. The value of `ablate` is that
|
|
308
|
+
its harness makes you *measure honestly*.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## API surface
|
|
313
|
+
|
|
314
|
+
| Component | What it does |
|
|
315
|
+
|-----------|--------------|
|
|
316
|
+
| `Ablator` | orchestrator: `extract(_subspace)` → `search(_subspace)` → `generate`/`harness`/`bake`/`save`/`push_to_hub` |
|
|
317
|
+
| `LM` | model + tokenizer wrapper with chat templating and generation |
|
|
318
|
+
| `extract_directions` / `extract_subspace` | single-direction and multi-direction (subspace) extraction |
|
|
319
|
+
| `AblationHooks` / `project_out` / `project_subspace` | runtime residual-stream ablation (1 or k directions) |
|
|
320
|
+
| `bake_direction` / `bake_subspace` | permanent weight orthogonalization (Linear + Conv1D) |
|
|
321
|
+
| `evaluate` / `mean_kl_divergence` / `refusal_rate` | intrinsic metrics |
|
|
322
|
+
| `Judge` / `KeywordJudge` / `LLMJudge` / `HFClassifierJudge` / `run_harness` / `compare` | benchmark + judge harness (ASR) |
|
|
323
|
+
| `optimize` / `optimize_subspace` | Optuna search over the intervention hyperparameters |
|
|
324
|
+
| `data.load_hf` / `load_harmbench` / `load_advbench` / … | HuggingFace dataset loading |
|
|
325
|
+
| `push_to_hub` / `build_model_card` | publish an abliterated checkpoint |
|
|
326
|
+
| `AblationConfig` / `SubspaceConfig` / `RunConfig` | typed configuration |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Extending it
|
|
331
|
+
|
|
332
|
+
- **Other behaviors.** Swap the prompt sets in `src/ablate/_data/` (or pass your
|
|
333
|
+
own lists to `extract`) to target sentiment, a persona, a language, etc. The
|
|
334
|
+
machinery is behavior-agnostic.
|
|
335
|
+
- **Bigger datasets.** `data.load_advbench()` / `data.load_alpaca_benign()` pull
|
|
336
|
+
from HuggingFace (needs `pip install ".[datasets]"`).
|
|
337
|
+
- **New architectures.** Add name mappings to `utils.get_decoder_layers` /
|
|
338
|
+
`get_residual_writers`.
|
|
339
|
+
- **Stronger judge.** `evaluate.is_refusal` is a substring matcher; drop in an
|
|
340
|
+
LLM/classifier judge for publication-grade eval, alongside HarmBench /
|
|
341
|
+
JailbreakBench prompts.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Tests
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
python tests/smoke_gpt2.py # numerical mechanism checks
|
|
349
|
+
python tests/e2e_instruct.py Qwen/Qwen2.5-0.5B-Instruct # single-direction refusal removal
|
|
350
|
+
python tests/e2e_subspace_harness.py # subspace ablation + judge harness
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Roadmap
|
|
354
|
+
|
|
355
|
+
- [x] multi-direction (subspace) ablation
|
|
356
|
+
- [x] HarmBench / AdvBench / JailbreakBench harness + LLM judge
|
|
357
|
+
- [x] direct HuggingFace dataset loading
|
|
358
|
+
- [x] one-call push to the Hub with a generated model card
|
|
359
|
+
- [ ] per-layer continuous α weights (not a single band)
|
|
360
|
+
- [ ] attention-head–level directions
|
|
361
|
+
- [ ] `pip`-installable release on PyPI
|
|
362
|
+
|
|
363
|
+
## Citation
|
|
364
|
+
|
|
365
|
+
If you use `ablate` in your research or projects, please cite it:
|
|
366
|
+
|
|
367
|
+
```bibtex
|
|
368
|
+
@software{ablate2026,
|
|
369
|
+
author = {AI Anytime},
|
|
370
|
+
title = {Ablate: A Directional Ablation (Abliteration) Toolkit for Language Models},
|
|
371
|
+
year = {2026},
|
|
372
|
+
url = {https://github.com/AIAnytime/ablate},
|
|
373
|
+
note = {Automatic censorship removal via residual-stream direction ablation}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Please also cite the paper this technique builds on —
|
|
378
|
+
[Arditi et al., 2024](https://arxiv.org/abs/2406.11717), *Refusal in Language Models
|
|
379
|
+
Is Mediated by a Single Direction*.
|
|
380
|
+
|
|
381
|
+
## Acknowledgements
|
|
382
|
+
|
|
383
|
+
Created with 💜 by **[AI Anytime](https://www.youtube.com/@AIAnytime)**. A full video
|
|
384
|
+
walkthrough is coming soon — subscribe on YouTube. Built on the mechanistic-interpretability
|
|
385
|
+
work of Arditi et al. and the open-source `transformers` / `optuna` ecosystems.
|
|
386
|
+
|
|
387
|
+
## License
|
|
388
|
+
|
|
389
|
+
MIT © AI Anytime.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
ablate/__init__.py,sha256=gR3RH6FN8zy-lEQBfUY1fVdlM6Sq6JW7xZyRKl4e3pI,1899
|
|
2
|
+
ablate/cli.py,sha256=T6y6C4wUja5aANOtFVwspM4xZSoyDfcqY-eGPDQooiA,7451
|
|
3
|
+
ablate/config.py,sha256=cbDvxbA1-c4w73w1HB97fYLMSbbYVC-hnacCMhYIN4o,3285
|
|
4
|
+
ablate/data.py,sha256=8qNHS268bfeMWqqlcIiKNH5lEOntZCKZtLaW1Su7LTM,4932
|
|
5
|
+
ablate/evaluate.py,sha256=6UCqW-HyTQot_z5eEWiKgB584VnFmDSGmaOSiLbfTbA,4649
|
|
6
|
+
ablate/extract.py,sha256=SVWdBvW3WNfMY9d0L573-5eEFVzo2ZcODRix7S08S4I,5106
|
|
7
|
+
ablate/harness.py,sha256=TnuW_wXTNN4LD3jwGU8dHY6L1qogFbspDM5ba10cPfk,3352
|
|
8
|
+
ablate/hooks.py,sha256=LLuL9h7Nx6RliNosV0qv8oB_WLrN3MlqAUK1bQWpx3o,2565
|
|
9
|
+
ablate/hub.py,sha256=Qc32VG02Ib6SEROfHo8hEaZutTXjIx1Kcuee_mxWP8w,5935
|
|
10
|
+
ablate/judges.py,sha256=Yl0Rd4Vt3A6vdRwVZvPfsG-enP5CcCGI-ubtuDySvv8,7208
|
|
11
|
+
ablate/model.py,sha256=nb_TNW38tps4eBlmw4SL4pdYkZ77mDIU-n5y7ZdbnSo,3536
|
|
12
|
+
ablate/optimize.py,sha256=DnUKNyptc_HAJqeArmVItVw6Fd_bieBBVENODO1vkbg,6196
|
|
13
|
+
ablate/pipeline.py,sha256=aS1FGHuQU_cPEHV9oNRJ8ZBdvE1EYPbunOy3MkKjdqw,14317
|
|
14
|
+
ablate/subspace.py,sha256=etCXXyRBXg6EFqgan2896kOj0v_lKuRR_W5R9Ii6AFI,4168
|
|
15
|
+
ablate/utils.py,sha256=onJtRafDoMM4o1f6ekdF1QB5e7pnW3tfoFeR55edQa4,4608
|
|
16
|
+
ablate/weights.py,sha256=f5d1uVfp_d9U6qEQtFch2_kx_VCqitM9iu-MP5Krnqc,2705
|
|
17
|
+
ablate/_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
ablate/_data/harmful.txt,sha256=7Fz88d1khheBiIvjB4PsJlZYKq3XyneadSdcS6D5z9s,2583
|
|
19
|
+
ablate/_data/harmless.txt,sha256=WcsVbNghZCOBsWipSD6rBI8bAqPayLKzZ601LTPFWiw,2485
|
|
20
|
+
ablate_llm-0.2.0.dist-info/licenses/LICENSE,sha256=dnjH_kfnDPZEe7jkku0eSJs-bQ8ZHX17Fn4tv8ooKBU,1067
|
|
21
|
+
ablate_llm-0.2.0.dist-info/METADATA,sha256=zuyXsST1_tx8I9FNnQ8u3icxqZaKLmIgNEcSVCgisXc,17043
|
|
22
|
+
ablate_llm-0.2.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
23
|
+
ablate_llm-0.2.0.dist-info/entry_points.txt,sha256=x1z57qco1J-lTd9XV-IhC3CZZxwyicwn-DVDOX6jlQI,43
|
|
24
|
+
ablate_llm-0.2.0.dist-info/top_level.txt,sha256=khWvSYuK7AaoXSm6RCmrX9FIaB7Yo701H34J2c4Bh2o,7
|
|
25
|
+
ablate_llm-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AI Anytime
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ablate
|