← 記事一覧

Abliterated モデルとは何か?

2026-08-20 · 1 分で読めます · abliteration, uncensored-models

abliterated モデルとは、通常のオープンウェイトモデルの重みを直接編集して、拒否挙動を外科的に取り除いたものです。再学習するわけでも、巧妙なプロンプトで包み込むわけでもありません。abliteration(ablate〈切除する〉と obliterate〈消し去る〉を組み合わせた造語)という名前は、その仕組みを正確に表しています。活性化空間の中で「これは断るべきだ」という情報を担っている単一の方向を特定し、ネットワークがその方向を二度と書き込めないようにするのです。

この手法は、チャット向けにチューニングされた Transformer における拒否が、主に1本の線形方向によって媒介されていることを示した解釈可能性研究から生まれました。この結果こそが、手法全体を安価にしている理由です。もし拒否が何千もの相互作用する特徴量に薄く広がっていたなら、それを取り除くには勾配降下法が必要になります。集中しているからこそ、線形代数で済むのです。

拒否は残差ストリームに宿る

Transformer の残差ストリームとは、トークン位置ごとに1本ずつ存在し、すべてのブロックが読み取っては書き戻していく累積ベクトルのことです。Attention ヘッドと MLP は自身の出力をそこに加算するだけで、上書きするものは何もありません。この加算的な構造のおかげで、残差ストリーム内のある方向は第10層でも第40層でもおおむね同じ意味を持ちます。だからこそ「拒否方向」を、40個のばらばらな方向ではなく単一の対象として語れるのです。

それを見つけるには、2種類のプロンプトセットが必要です。モデルが確実に拒否するものと、確実に答えるものです。両方を実行し、固定した層とトークン位置で残差ストリームの活性化を記録し(指示部分の末尾数トークンが適しています。モデルがリクエストを読み終え、まだ回答を始めていない位置だからです)、その平均の差を取ります。

python
import torch

def refusal_direction(harmful: torch.Tensor, harmless: torch.Tensor) -> torch.Tensor:
    """Difference-in-means estimate of the refusal direction, unit-normalised.

    Both tensors are [n_prompts, d_model] residual-stream activations captured at
    the same layer and token position. Difference-in-means beats a trained probe
    here: with a few hundred prompts a probe overfits, a mean shift does not.
    """
    r = harmful.mean(dim=0) - harmless.mean(dim=0)
    return r / r.norm()

これを候補となるすべての層と位置で行い、数十本の候補方向を得たうえで、1本を選びます。抽出よりも選択のほうが重要です。正しい基準は、その候補を除去したうえで、ホールドアウトした有害プロンプトでどれだけ拒否が減るかと、無害プロンプトで次トークンの分布がどれだけ動くかの両方を測ることです。後者の数値(通常は未改変モデルに対する KL ダイバージェンス)が、損傷の度合いを示すメーターになります。拒否は消せても無害側の分布を大きく歪めてしまう候補は、拒否の除去率がわずかに劣っても副作用がごく小さい候補より悪い選択です。

abliterated モデルはどう作られるか

単位ベクトル r が得られたら、使い方は2通りあります。1つ目は推論時のフックです。各層で、活性化のうち r 方向の成分を差し引いてから次に渡します。これでも動作しますが、実行時フックが必要になるため、モデルはもはや素のチェックポイントではなくなります。

2つ目が本来の abliteration で、これを重みに焼き込みます。残差ストリームに書き込むすべての行列(埋め込み行列、すべての Attention 出力射影、すべての MLP ダウン射影)に対して、出力空間から r を取り除くランク1の更新を施します。

python
def orthogonalize_(weight: torch.Tensor, r: torch.Tensor) -> None:
    """Project r out of a matrix that writes into the residual stream, in place.

    weight is [d_model, d_in]. After W <- (I - r rT) W, the product W @ x has zero
    component along r for every possible x, so no amount of prompting can put the
    direction back. Rank-one per matrix; no gradients, no optimiser, no dataset of
    answers — only the few hundred prompts used to estimate r.
    """
    weight -= torch.outer(r, r @ weight)

結果として得られるのは、ごく普通のチェックポイントです。アーキテクチャもファイル形式も推論コストも同じで、vLLM や llama.cpp にそのまま読み込めます。GPU 1枚で手順全体が数分で終わり、時間がかかるのは候補の走査であって、編集そのものではありません。

ファインチューニングとの違い

拒否を取り除くためのファインチューニング(従順な応答のコーパスに対する SFT や DPO)は、根本的に異なる操作です。勾配降下法ですべての重みを動かし、プロンプトだけでなく回答のデータセットを必要とし、GPU 時間を消費し、既存の挙動を削除するのではなく新しい挙動を教え込みます。さらに、ファインチューニング用コーパスに含まれる文体や長さの偏り、事実に関する癖まで一緒に引きずり込み、無関係な能力の破滅的忘却を起こすリスクもあります。

abliteration が触れるのは1つのランク1部分空間だけで、それ以外には何もしません。この精密さが最大の売りであると同時に、主な失敗モードの源でもあります。もし拒否以外の何かがたまたま r に沿って存在していれば、それも一緒に破壊されてしまい、候補の走査をどれだけ慎重に行っても完全には避けられません。

ジェイルブレイクプロンプトとの違い

ジェイルブレイクは重みには手を付けず、代わりに活性化を拒否回路が発火しない領域へ誘導します。これは、自動化において致命的な形で脆いのです。呼び出しのたびにコンテキストトークンを浪費します。非決定的で、同じプロンプトがあるサンプルでは従い、次のサンプルでは拒否することがあります。プロバイダーがモデルを更新したり、特定の言い回しに対策を打ったりすると、何の通知もなく壊れます。そして拒否の仕組みが完全に残っているため、生成の途中で息を吹き返すことがあり、有用な出力が3段落続いた後に「やはり、これ以上は続けられません」と来るわけです。

abliterated モデルには、息を吹き返すものが何もありません。挙動は生成全体を通しても、プロンプトの言い回しを変えても安定しており、この性質こそがバッチパイプラインで使い物になる理由です。

トレードオフには正直に

abliterated モデルは、より優れたモデルではありません。「ノー」と言わなくなったモデルであり、それは聞こえるよりずっと限定的な主張です。

公開されている abliterated モデルの多くは、劣化した能力を取り戻すために後から軽い修復用ファインチューニングを施されています。これは、この手法が避けるはずだったコストをひっそりと再導入していることになります。

どこで役に立つのか

正直な用途は、拒否が安全性の成果ではなく測定誤差になる仕事です。レッドチーミングのハーネス、拒否率のベースライン、頑健性評価、そして題材がガードレールに引っかかるものの作業自体は防御的なセキュリティ分析などです。unbleep は abliterated モデルを OpenAI 互換エンドポイントの背後で提供しているので、既存のクライアントを向けるだけで安定したベースラインが得られます。それを使って何を作るかはあなたの責任です。私たちが越えない一線については利用ポリシーをご覧ください。

API キーを取得して、その違いをご自身で測ってみてください。