Digital Reactor
機械学習

出力を読まずに嘘を見つけられるか:線形プローブでLLMの内部状態を読む

出力を読まずに嘘を見つけられるか:線形プローブでLLMの内部状態を読む

はじめに

生成AIの出力を利用者に返す前に、別のLLMへ「この回答は事実に反していないか」と確認させる。品質チェックの運用として、いまいちばんよく見る形です。動きはするのですが、出力1件ごとに判定用の呼び出しがもう1回走るので、コスト効率はよくありません。判定を待つぶんの遅延も利用者への応答に上乗せされます。

見落とされがちなのは、判定に使える情報の一部が、すでに手元にあることです。出力を作ったモデルは、生成の途中で各層の内部状態(活性、activation)を計算し終えています。文の真偽がそこに線形な形で、つまりベクトルの内積1回で読み出せる形で埋まっているなら、監視のためにもう1本のLLMを回す必要はありません。実際にそうなっていることを示したのがGeometry of Truth(Marks & Tegmark, 2023)で、Apollo Researchはこの延長で、モデルが意図的に嘘をつく場面すら活性から検出できることを報告しています。

ただし、これらの結果は13Bから70B級のモデルで確認されたものです。この記事では、CPUだけで動く0.5Bの小型モデル(Qwen2.5-0.5B-Instruct)と自作の真偽文データで、この一連の観察がどこまで再現できるかを実験します。結論を先に言うと、中間層の活性を入力に線形プローブ(linear probe。単純な線形分類器です)を1本訓練するだけで、英日翻訳の真偽文は97%当てられました。一方で、訓練に使ったデータの外へ出ると精度はほぼ半分(あて推量と同水準)まで落ち、論文が大型モデルで報告した「データセットをまたぐ汎化」は再現できませんでした。どこまでが小型モデルでも成り立ち、どこからが成り立たないのかを、順に確かめていきます。

対象読者:

  • LLM出力の品質・安全チェックを別のLLM判定で回していて、コストと遅延に課題を感じている方
  • モデル内部の活性を使った監視がどこまで実用になるか、根拠を持って判断したい機械学習エンジニア
  • 生成AIの監視設計を検討している信頼性・リスク管理の担当者

記事のポイント:

  • 真偽文3種(都市と国・数値の大小・英日の単語対応)を0.5Bモデルに読ませ、中間層の活性から線形プローブで真偽を分類できることを確認します
  • 分類精度で勝るロジスティック回帰プローブと、クラス平均の差で作る単純なプローブ(difference-of-means)が違う方向を向くことを示し、どちらがモデルの出力を実際に動かすかを介入実験で比べます
  • 訓練データの外での性能低下と判定コストを実測し、プローブ監視を実務に載せるときに壊れる箇所を整理します

「パリはフランスの都市です」が1本のベクトルになるまで

抽象的な話に入る前に、1つの文がプローブのスコアになるまでを実物の値で追います。対象は「パリはフランスの都市です。」という真の文です。

トークナイザに通すと、この文は8トークンに分かれます。それをモデルに入れて1回だけ順伝播(forward)させると、埋め込みと24層それぞれの後で、トークンごとに896次元のベクトルが得られます。transformersでは output_hidden_states=True を渡すだけで、この中間状態が全部返ってきます。

inputs = tokenizer("パリはフランスの都市です。", return_tensors="pt")  # 8トークン
out = model(**inputs, output_hidden_states=True)
# out.hidden_states は (埋め込み + 24層) のタプル。各要素は (1, 8, 896)
x = out.hidden_states[14][0, -1]  # 層14、最終トークン「。」の位置の活性化

文全体の情報がいちばん集まるのは最後のトークンの位置なので、層14の最終トークン「。」の位置から896次元のベクトルを1本取り出します。これがこの文の活性 xx です。中身の先頭5個は次のようになっています。

x = [0.049, -0.078, -0.870, 0.045, -0.125, ...]   # パリはフランスの都市です。

同じ操作を偽の文「パリはドイツの都市です。」にすると、こうなります。

x = [0.038, -0.064, -0.936, -0.032, -0.079, ...]  # パリはドイツの都市です。

眺めても真偽の違いは読み取れません。896次元のうちどこか特定の座標に「真偽フラグ」が立っているわけではなく、違いは多数の座標に薄く分散しています。線形プローブは、この分散した違いを1本の方向ベクトル wR896w \in \mathbb{R}^{896} に集約する仕掛けで、スコアは内積1回で出ます。

f(x)=σ(wx+b)f(x) = \sigma(w \cdot x + b)

σ\sigma はシグモイド関数、bb は切片です。文の真偽ラベルを yy(真なら1、偽なら0)とすると、プローブの訓練とは、ラベル付きの活性の組 (x,y)(x, y) を集めて wwbb を決めることを指します。この記事の後半で、都市と国の文600件から訓練するプローブにこの2文を通すと、真の文は f(x)=0.977f(x) = 0.977、偽の文は f(x)=0.093f(x) = 0.093 になります。閾値を0.5に置けば、どちらも正しく判定できています。

「パリはドイツの都市です。」が層14の活性を経て線形プローブに入り、スコア0.093で偽と判定されるまでの流れ。

ここで押さえておきたいのは、この判定に追加の生成が一切要らないことです。活性 xx は、モデルがこの文を処理した時点で計算済みです。判定のための追加コストは、896次元の内積1回にすぎません。あとは、この方向 ww をどう見つけるか、どの層から xx を取るか、そしてこの判定がどこまで信用できるかの問題になります。

真偽はどの層に現れるか

先ほどは断りなく層14からベクトルを取り出しましたが、この選択には根拠が要ります。まず実験の材料を揃えます。真偽のラベルが機械的に決まる文を3種類、テンプレートから合成しました。

データセット真の文の例偽の文の例件数
都市と国パリはフランスの都市です。パリはマレーシアの都市です。600
数値の大小67は64より大きい。5は18より大きい。552
英日の単語対応英語のdogは日本語の犬にあたる。英語のdogは日本語の名前にあたる。520

いずれも真偽半々で、訓練70%・テスト30%に分けます。同じ都市や単語が訓練とテストの両側に出ないよう、分割は文単位ではなく都市・単語の単位で行いました。もう1つ、データの作り方に仕込みがあります。同じ都市名・国名・単語が真の文にも偽の文にも登場するので、どの単語が含まれるかを数えるだけでは真偽を当てられません。真偽は語の組み合わせが事実と合っているかどうかにしか現れない構成です。

都市と国を例に、合成のコードを示します。1つの都市から真の文2本と偽の文2本を作り、どの都市から作った文かの番号(entity)を分割用に持ち回ります。

def build_cities():
    countries = sorted(set(c for _, c in CITIES))  # CITIES = [("パリ", "フランス"), ...]
    stmts, labels, entity = [], [], []
    for i, (city, country) in enumerate(CITIES):
        wrongs = [c for c in countries if c != country]
        w1, w2 = rng.choice(wrongs, size=2, replace=False)
        stmts += [
            f"{city}{country}の都市です。",
            f"{city}{country}にあります。",
            f"{city}{w1}の都市です。",
            f"{city}{w2}にあります。",
        ]
        labels += [1, 1, 0, 0]
        entity += [i] * 4
    return stmts, np.array(labels), np.array(entity)

この3種それぞれについて、埋め込み層から最終層まで25箇所すべてで最終トークンの活性を取り、各層でLRプローブ(ロジスティック回帰、次の節で説明します)を訓練してテスト精度を測りました。

層ごとの線形プローブ精度。埋め込み層では0.5前後、中盤の層で立ち上がり、層14前後で頭打ちになる。

代表的な層だけ抜き出すと次のとおりです。以降の実験では、3データセット平均が最大に最初に到達した層14を使います。

都市と国数値の大小英日の単語対応平均
0(埋め込み)0.5000.4970.5000.499
40.5830.8730.5580.671
80.6890.9030.8460.813
100.7000.9150.9740.863
140.7670.9330.9680.889
200.7110.9210.9620.865
24(最終層)0.6280.9760.9620.855

埋め込み層(層0)の精度がほぼ0.5であることは、先ほどの仕込みが機能した確認になります。単語の並びを写しただけの表現には真偽の情報がなく、あて推量と変わりません。層を進むと精度が立ち上がり、中盤で頭打ちになります。立ち上がる場所はデータセットで違い、数値の大小は層5ですでに0.94に達するのに対し、単語対応は層9まで、都市と国は層14までかかります。数の比較のような単純な照合は浅い層で済み、知識との突き合わせが要る文ほど深い層まで組み上がらない、という順序です。

都市と国は最終層に向けてむしろ下がっていく点も見逃せません。終盤の層は次のトークンを出す準備に表現を組み替えていくため、「深いほど情報が濃い」とは限らず、層の選択はこうして測って決める必要があります。

選んだ層で活性がどう分布しているかを、教師なしの次元圧縮でも見ておきます。単語対応と都市と国それぞれの全文の活性(896次元)を、ラベルを一切使わずに主成分分析(PCA)で2次元へ落としました。

層14の活性のPCA散布図。左の単語対応では真の文と偽の文が第2主成分方向に分かれるが、右の都市と国では分かれない。

左の単語対応では、ラベルを与えていないのに、第2主成分の上下で真偽がはっきり分かれます。横方向の2つの塊は真偽ではなく文のテンプレート(「〜にあたる」と「〜という意味です」)の違いで、活性の分散としては真偽よりも言い回しのほうが大きいことも読み取れます。一方、右の都市と国では上位2成分のどこにも真偽の構造が見えません。プローブ精度が0.767止まりだったことと符合していて、このモデルは単語の対応関係ほどには都市と国の知識を強く表現していないようです。Marks & Tegmarkは13Bモデルで、どのデータセットでも上位主成分に真偽の分離が現れることを報告していますが、0.5Bでは題材を選ぶ、というのが実際に測って分かる差です。

差の平均とロジスティック回帰は違う方向を向く

方向 ww の見つけ方は1つではありません。ここでは対照的な2つを訓練して比べます。

1つ目は、Geometry of Truthの論文でmass-mean probingと呼ばれている方法で、実装は2行で書けます。真の文の平均活性から偽の文の平均活性を引いた差を、そのまま方向にします(以下MMプローブと呼びます。difference-of-meansとも呼ばれます)。

def fit_mm(X, y):
    mu_t = X[y == 1].mean(axis=0)   # 真の文の平均活性化
    mu_f = X[y == 0].mean(axis=0)   # 偽の文の平均活性化
    w = mu_t - mu_f                 # クラス平均の差がそのまま方向
    b = -w @ (mu_t + mu_f) / 2      # 2つの平均の中点で判定を切る
    return w, b

2つ目はロジスティック回帰(以下LRプローブ)で、scikit-learnの LogisticRegression をそのまま使います。こちらは分類の損失を最小化するので、真偽の分離に役立つ違いなら何でも拾いにいきます。訓練のコードはこれだけです。

def fit_lr(X, y):
    lr = LogisticRegression(max_iter=2000)
    lr.fit(X, y)
    return lr

3つのデータセットそれぞれで、訓練分割から両方のプローブを作り、テスト分割の精度と、2本の方向ベクトルの余弦類似度(cosine similarity)を測りました。

データセットLRプローブ精度MMプローブ精度方向の余弦類似度
都市と国0.7670.6780.563
数値の大小0.9330.7030.728
英日の単語対応0.9680.9620.780

分類精度はLRの勝ちです。特に数値の大小では23ポイントの差がつきました。これ自体は当然の結果で、LRは分類精度を直接最適化しているのに対し、MMは2つのクラスの重心を結んだだけだからです。

見るべきは3列目です。同じデータ・同じ層で訓練したのに、2本の方向の余弦類似度は0.56から0.78にとどまります。896次元の空間で無関係な2本のベクトルの余弦類似度はほぼ0なので、2本が同じ側を向いているのは確かですが、重なってもいません。「真偽を当てる」という同じ課題を解きながら、LRとMMは活性空間の違う方向を見ています。どちらが「モデルが実際に使っている方向」に近いのかは、分類精度からは決められません。この疑問は介入実験の節で確かめます。

訓練したデータの外で何が起きるか

監視に載せる場面を考えると、プローブが判定する文は訓練に使った文と同じ種類とは限りません。むしろ、想定していなかった話題での誤りをこそ捕まえたいはずです。そこで3つのデータセットで訓練と評価を総当りにして、LRプローブの精度を測りました。行が訓練に使ったデータ、列が評価先です。

クロスデータセット汎化行列。対角成分は0.77から0.97だが、非対角成分は都市→単語対応の0.73を除いてほぼ0.5に落ちる。

対角成分(訓練と同じ種類のデータでの評価)は前節のとおり0.77〜0.97です。ところが非対角成分は、都市と国で訓練して英日の単語対応を判定した0.73を除き、0.50前後まで落ちます。0.5はコイン投げと同じ、つまり何も判定できていません。数値の大小に至っては、どちらの向きにも転移しません。数値で訓練したプローブは他を判定できず、他で訓練したプローブは数値を判定できません。

Geometry of Truthの論文は13Bモデルで「LRプローブはほぼ完全に転移する」と報告し、モデルの規模が大きくなるほど真偽の表現がデータの種類をまたぐ抽象的なものになることを示しています。今回の0.5Bにはその「共通の真偽方向」がまだ育っておらず、プローブが拾っているのはデータセットごとに別の特徴だと解釈できます。プローブ監視を小型モデルに適用するなら、この点だけで設計が変わります。監視したい話題ごとに訓練データを用意する必要があり、「1本のプローブで嘘全般を見張る」という期待は規模の大きいモデルでしか成立しません。

行列の数字だけでは、誤りがどんな文で起きるのかが見えないので、都市と国のテスト文からプローブスコアの実例を抜き出します。判定は閾値0.5で切ったもの、「実際」は文の真偽です。

プローブスコア f(x)f(x)判定実際
大阪は日本にあります。0.997
ニューヨークはアメリカの都市です。0.995
オークランドは日本にあります。0.877
ビルバオはニュージーランドにあります。0.525
マルセイユはフランスにあります。0.506
ブルノはチェコの都市です。0.081

大阪やニューヨークのような有名都市は、スコア0.99以上で迷いなく正解します。誤りが出るのは知名度の低い都市で、ブルノがチェコの都市だという真の文は0.081と、確信を持って偽と判定されました。逆にオークランドが日本にあるという偽の文は0.877で通っています。誤りの並びを見ると、プローブが読み出しているのは「文が客観的に正しいか」ではなく「モデルがその文を真として表現しているか」だと分かります。モデル自身がブルノとチェコを結びつけて覚えていなければ、活性のどこにも真の信号は存在しません。プローブの誤りは、モデルの知識の穴とそのまま対応していそうです。

監視に使うときは、この性質は弱点にも利点にもなります。モデルの知識不足による誤答を捕まえたいなら好都合ですが、世の中の事実と突き合わせるファクトチェックの代わりにはなりません。

精度の数字をもう1段疑う材料として、教師なしでこの方向を見つけると称する手法の顛末にも触れておきます。CCS(Contrast-Consistent Search、Burns et al. 2022)は、文とその否定のペアに対して「肯定が真である確率と否定が真である確率の和が1に近い」という一貫性を損失にし、ラベルなしでプローブを訓練する手法です。ラベル付けが不要という触れ込みで注目されましたが、その後の検証で本質的な弱点が指摘されました。

Emmons(2023)は、ペアの活性の差ベクトルにPCAをかけるだけでCCSの精度のおよそ97%が出ること、つまり損失関数ではなくコントラストペアの構成が仕事のほとんどを担っていることを示しました。Farquhar et al.(2023)は、どんな2値分類に対しても損失ゼロのCCSプローブが存在することを証明したうえで、ペアに無関係な単語を混ぜるとCCSは真偽ではなくその単語のほうを分類してしまうと報告しています。さらにMarks(2024)は、LLMが任意の特徴どうしのXOR(排他的論理和)まで線形に表現していることを示しました。プローブが「真偽と話題のXOR」のような合成方向を拾っていても、訓練データの範囲では見分けがつかず、分布が変わった途端に崩れます。教師ありのプローブですら上の行列のとおり転移しないのですから、単一データセットでの精度は、教師のあるなしにかかわらず、それだけでは何も保証しないと考えておくべきです。

分類できることと、モデルがそれを使っていることは別

97%という分類精度は、活性と真偽の相関を示しているだけです。モデル自身がその方向を「真偽の判断」として出力の計算に使っている保証はどこにもありません。XORの議論が示すとおり、たまたま分離に役立つだけの合成的な特徴を拾っていても、分類精度は同じように出ます。監視の道具として信用するには、その方向を動かすとモデルの出力が動く、という因果の証拠が欲しいところです。

そこでGeometry of Truthの介入実験を再現します。まずモデル自身に真偽を判定させる課題を用意します。真偽4例ずつの手本を並べた後に判定したい文を置き、「 This statement is: 」に続く次のトークンとして TRUE と FALSE のどちらを出すか、その確率差 P(TRUE)P(FALSE)P(\mathrm{TRUE}) - P(\mathrm{FALSE}) を測ります。課題は英日の単語対応にしました。この0.5Bモデルは、都市と国や数値の大小ではこの判定があて推量と変わらず(正解率0.50と0.43)、単語対応でだけ手本8例で0.858まで正解できたためです。手本を4例に減らすと判定が TRUE 側へ偏ったので、真偽4例ずつの8例に揃えています。

そのうえで、判定の途中に手を入れます。文を処理している途中の残差ストリーム(residual stream、各層の出力が積み上がっていく本流のベクトル列)に、プローブ方向を足し引きします。forward hookで層8から14の出力に対し、文末の「。」とその直後のトークン位置へ、スケールした方向ベクトルを加算するだけです。スケールは、真偽それぞれの平均活性の差をプローブ方向に射影した長さ、つまり「真偽の重心の隔たり1個分」にしています。

def hook_fn(module, inp, output):
    hs = output[0] if isinstance(output, tuple) else output
    for b in range(hs.shape[0]):
        end = int(attn[b].sum())
        # 文末の「。」と、直後の This の2トークン位置に介入
        hs[b, end - len_suffix - 1] += sign * dir_t
        hs[b, end - len_suffix] += sign * dir_t
    return (hs,) + output[1:] if isinstance(output, tuple) else hs

偽の文に「真の方向」を足したとき、真の文から引いたときに、判定がどれだけ動いたかをまとめます。評価は手本に使った単語を除くテスト文120件(真偽60件ずつ)です。

条件対象平均 P(TRUE)P(FALSE)P(\mathrm{TRUE})-P(\mathrm{FALSE})TRUEと判定される割合
介入なし真の文+0.24198.3%
介入なし偽の文−0.18026.7%
MM方向を加算偽の文+0.12493.3%
LR方向を加算偽の文+0.03260.0%
MM方向を減算真の文−0.2060.0%
LR方向を減算真の文−0.2570.0%

介入前後のP(TRUE)-P(FALSE)分布。左は偽の文に真の方向を加算した場合で、MM方向は分布を正側へ大きく押し出す。右は真の文から減算した場合で、両方向とも負側へ移る。

介入は効いています。MM方向を足すと、TRUEと判定される偽の文は26.7%から93.3%まで増えました。文そのものは1文字も変えていないのに、内部のベクトルを1方向動かすだけでモデルの判定が反転します。この方向が単なる相関ではなく、モデルが真偽の判断に実際に使っている表現だという因果の証拠です。

そして、プローブの種類で効き方に差が出ました。偽の文に方向を足す条件では、MM方向がLR方向を大きく引き離します(判定が変わる割合で93.3%対60.0%、判定値の動きで+0.304対+0.213)。分類精度ではLRが上回っていたにもかかわらずです。Geometry of Truthは13Bモデルで「分類精度で劣るMMプローブのほうが因果的に強い」という逆転を報告しており、その逆転が0.5Bのこの条件でも観察できました。一方、真の文から引く条件ではどちらの方向でも全件がFALSE判定になり、効果が飽和して差がつきませんでした。

この逆転には筋の通った説明があります。LRは分類の損失を最小化するので、真偽と相関する特徴なら、モデルが判断に使っていないものでも重みを載せます。MMは真偽それぞれの重心の差、つまり「真の文と偽の文で活性が平均的にどう違うか」そのものなので、モデルが読み書きしている表現の向きそのものに沿います。読み出し(分類)に良い方向と、書き込み(介入)に効く方向は別物で、監視のためにプローブを選ぶときも、分類精度だけを基準にすると因果的には的外れな方向を選びかねません。

監視に載せるとしたらどこで壊れるか

ここまでの結果を、冒頭の運用の話に戻して整理します。

コストの差は実測で出ています。同じ0.5Bモデルに手本付きで判定させるLLM判定は、出力1件につきもう1回の推論が走り、今回のCPU環境では1件あたり1.8秒かかりました。プローブは、生成時に計算済みの活性と方向ベクトルの内積を1回計算するだけなので、同じ環境の実測で1件あたり0.15マイクロ秒、およそ1,000万倍の差です。この比は負荷や実装で大きく動く参考値ですが、フル推論1回と内積1回という構造の差は、どの環境でも桁違いのまま残ります。推論基盤を自社で持っているなら、生成のついでに中間層1層分の最終トークンの活性をログへ流すだけで、監視の追加計算は事実上なくなります。裏返すと、この方法は活性に触れられることが前提で、API越しにしか使えないモデルには適用できません。

LLM判定と線形プローブの構造の違い。上段は生成した回答を判定用LLMにもう1回読ませる方式で、実測1.8秒/件。下段は生成時に計算済みの内部状態と方向ベクトルの内積を1回計算するだけで、実測0.15マイクロ秒/件。

閾値の設計には注意が要ります。プローブのスコアは0から1に収まりますが、確率として校正されているわけではありません。スコア0.9の文を集めても実際に真が9割になる保証はなく、閾値判定や期待損失の計算に使う前には確率の校正を挟む必要があります。閾値そのものは、見逃し(偽の文を通す)の損失と、誤検知(真の文を人手レビューに回す)の作業コストの比で決めます。ブルノの例で見たとおり、このプローブは知名度の低い固有名詞まわりで系統的に外すので、スコアだけでなく入力側の性質と組み合わせた運用設計が現実的です。

分布シフトへの弱さは、汎化行列がそのまま答えです。訓練したデータの外では0.5まで落ちうるので、監視対象のドメインごとにコントラストペアの訓練データを作り、ラベル付きの評価データで定期的に測り直します。さらにプローブ特有の事情として、基盤モデルを差し替えたりファインチューニングしたりすると活性空間ごと変わり、手持ちのプローブはすべて無効になります。モデルのバージョンとプローブのバージョンは対で管理し、モデル更新のたびにプローブの再訓練と再評価をリリース手順へ組み込むことになります。

最後に、構造的にいちばん深い問題を挙げます。プローブのスコアを、モデルを訓練する目的関数に入れてはいけません。プローブが検出する内部信号を減らす方向へモデルを最適化すると、嘘が減るのではなく、プローブに映らない形へ内部表現が再配置されるだけに終わる懸念(obfuscated internals、内部表現の難読化)が指摘されています。Apollo Researchも、プローブ監視は有望としながら、現状の性能は欺瞞への防御として単体で頼れる水準ではないと明記しています。1本の方向を見張るプローブの代わりに、SAE(sparse autoencoder)で活性を解釈可能な特徴に分解して監視する選択肢もありますが、監視シグナルを訓練に流用しないという原則はどの道具でも変わりません。

まとめ

出力を読まずに嘘を見つけるという発想は、0.5Bの小型モデルとCPUだけでも骨格を確かめられました。中間層の最終トークンの活性を線形プローブに通すと、モデルがよく知っている題材(英日の単語対応)では97%の精度で真偽を読み出せます。判定の追加コストは内積1回で、LLM判定との差は実測でおよそ1,000万倍でした。介入実験では、活性に方向ベクトルを1本足すだけで偽の文のTRUE判定が3割弱から9割超まで増え、この方向がモデルの判断に因果的に関与していることまで確認できました。分類精度で勝るLRプローブより、クラス平均の差で作ったMMプローブのほうが介入で強く効くという論文の逆転も、足す向きの条件では0.5Bで再現しています。

同時に、この道具の限界も同じ実験の中で数字になりました。プローブが読むのはモデルの内部表現であって世の中の事実ではなく、モデルの知識が薄い題材では確信を持って外します。訓練したデータの外へ出ると精度はあて推量まで落ち、0.5Bには論文が大型モデルで報告したデータ横断の真偽方向は見つかりませんでした。プローブ監視を検討するなら、まず監視対象のタスクそのものから真偽のコントラストペアを数百件作り、手元のモデルの中間層で対角成分の精度(訓練と同じ種類のデータでの精度)を測るところから始めてください。その数字が十分高いと確かめられてから、閾値・校正・再訓練の運用設計へ進んでも遅くありません。

関連記事

← 技術ブログ一覧へ