LessWrong > Activation Engineering
有害命令と無害命令を入れて差分取ると「拒否方向」が取れるロジック
https://scrapbox.io/files/673765d94eef1dcb13f9c851.png
分離できるから線形で分離できる仮説援護できるのでは
これの可視化の意味、つまりはHarmlfulとHarmlessのアクティベーションを生のままとってみて、そのクラスタを表示しているわけなので、これらのクラスタが分離できている = 意味のあるベクトルすなわち方向が現れるという意味である
https://scrapbox.io/files/67376d8a98bb3d3feb2b41e0.png
微調整によってモデルの重みを永続的に変更することでアクティベーション ステアリングの概念を拡張し、入力ごとにアクティブ ステアリングを行う必要性を排除します
https://scrapbox.io/files/673908b94c5ba196f024342d.png
GPT の確率予測は、最終層のアクティベーションの線形関数です。同じ関数を中間GPT 層のアクティベーションに適用すると、結果の分布は直感的に理解できます
そうっぽい
全体の流れ概要書いてるの良いね
最初のステップ: 例と反例を示す2つの文を選択する3何らかの要求に対する 拒否/承諾 。最初の文は拒否の行動、2番目の文は まったく同じ文脈で承諾の行動を 2 番目のステップ: 上記の文に対して実行されたときの LLM の (隠れた) 活性化パターンのスナップショットを取得します。このようなスナップショットは多層構造になっており、各層は長いベクトル (活性化ベクトルと呼ばれる) で表されます。
3 番目のステップ: 各レイヤーについて、最初のベクトル (拒否の例に関連) を 2 番目のベクトル (承認の例に関連) から減算して、3 番目のベクトルを取得します。
4 番目のステップ: ランダム ノイズを除去するには、さまざまな文のペアに対してこのプロセスを繰り返し、各列が上記のベクトルの 1 つである行列を形成します。
5番目のステップ:線形代数(PCA)を使用して、上記の行列の支配的な方向を見つけます。これは、大きな正方行列の最長の固有ベクトルを計算するのと似ています。これが推定された制御ベクトルです。4固有値の平均長はベクトルの品質を評価するのにも役立ちます(AIの安全性レベルの定量的な推論に役立つ可能性があります)。 最後のステップ: 次のプロンプトで、 活性化状態における制御ベクトルの方向を人工的に強化 (または減少) します。
「正直さ」の制御ベクトルと「偽りの正直さ」の制御ベクトルを比較することで、モデルがそれらを同じとみなすかどうかを知ることができます
★ベクトル同士を何かしらで類似度はかる
プロジェクションの結果を比較する方法は、制御ベクトルを使って入力や隠れ状態から得られるスコア(プロジェクションスコア)を解析することで、モデルが異なる概念(例: 正直さと見せかけの正直さ)をどのように区別しているかを理解する手法です。
プロジェクションの計算手順
1. 制御ベクトルの取得
• 正直さや見せかけの正直さを表すための制御ベクトル \mathbf{v}{honesty} , \mathbf{v}{feigned\_honesty} を事前に計算します。
2. 隠れ状態の取得
• 言語モデルに入力文を通し、隠れ状態(hidden state)を取得します。たとえば、隠れ状態を \mathbf{h} とします。
3. スコア計算 (プロジェクション)
• 各入力文に対し、制御ベクトルを使ってスコア(プロジェクションスコア)を計算します。
• スコアの計算式:
\text{Projection Score} = \mathbf{v} \cdot \mathbf{h}
• \mathbf{v} : 制御ベクトル
• \mathbf{h} : 入力文の隠れ状態
• このスコアは、隠れ状態が制御ベクトルの方向にどれだけ近いかを示します。
4. スコア分布の取得
• 多数の入力文に対してスコアを計算し、各制御ベクトル(正直さや見せかけの正直さ)のスコア分布を得ます。
分布の比較手法
1. スコア分布の可視化
• スコアの分布をヒストグラムや密度プロットとして視覚化。
• 例:
• \mathbf{v}_{honesty} に対するスコアは正の値に集中。
• \mathbf{v}_{feigned\_honesty} に対するスコアが負の値に広がる場合、モデルが異なる方向性で概念を捉えている可能性を示します。
2. 重なりの評価
• スコア分布がどれだけ重なっているかを測定します。
• 使用する指標:
• KLダイバージェンス:
D_{KL}(P \| Q) = \sum P(x) \log\frac{P(x)}{Q(x)}
• P(x) : \mathbf{v}_{honesty} のスコア分布
• Q(x) : \mathbf{v}_{feigned\_honesty} のスコア分布
• 値が大きいほど、分布が異なる。
• Wasserstein距離:
• 2つの分布間の「移動コスト」を測定する距離。
• 小さいほど、分布が似ている。
3. 分類性能の評価
• 入力文のスコアを分類器にかけ、「正直さ vs 見せかけの正直さ」を分類させます。
• 分類精度が高い場合、制御ベクトルが概念を正確に区別している可能性を示します。
https://scrapbox.io/files/67391e63dc8eb00671c0596c.png
脱獄ベクトル足した場合とたさない場合の差分をPCAして可視化
中間層の最終トークン
ランダムなアクティベーションのペア間の差の最初の主成分を取得します
LLM からアクティベーションを読み取ってパッチを適用するには、まず、必要な関連レイヤーを見つけて、フックを追加するかラップする必要があります。これにより、2 つのアプローチが考えられます。1. 作業する可能性のあるすべてのモデルに対してカスタム モデル ラッパーを作成する ( Repe、CAAが採用しているアプローチ)、または 2. パッチを適用するレイヤー名を手動で指定することをユーザーに任せ、Pytorch フックを使用してパッチを適用する ( Baukitが採用しているアプローチ)。最初のアプローチは、新しいモデルがリリースされるたびに終わりのない戦いになります。2 番目のアプローチは、非常に柔軟ですが、作成したものを使用するすべての人に複雑さが伝わります。
はい
この投稿では、3 番目のオプションについて説明します。これは、Pytorch LLM のレイヤーの種類を自動検出し、Pytorch フックを使用して読み取り/パッチを行うというものです。これは、steering-vectorsライブラリで使用されているアプローチです。これは、すべてのトランスフォーマー LM が同じ基本構造 (アテンションと MLP ブロックを含む一連のレイヤー) を持っているという事実を活用します。 ステアリングベクトルの生成に使用するデータには、 StereoSet Dataset を使用しました。これは、さまざまなドメインにわたるステレオタイプバイアスを測定することを目的とした大規模な自然英語データセットです。さらに、性別バイアスプロンプトのセットをカスタム作成し、chatGPT 4 を使用して同様の例を生成しました。次に、これらすべての例を複数選択の A/B 質問に再フォーマットしました (性別データは こちら、StereoSet データは こちら)。以下の例では、プロンプトに (A) を追加することで、モデルが偏った動作をするように条件付けることができ、その逆も可能です。
生成されたステアリング ベクトルとフォワード パス中の通常のアクティベーション間のコサイン類似度を計算して、生成されるテキストが「拒否にどの程度似ているか」を確認できます。これを生成されたトークンに対応させて、ステアリング ベクトルとの類似性が、どのトークンを拒否の概念に直感的に関連付けるかを反映しているかどうかを確認できます。
ここにコード書いてる。reset_allしてから可視化しているので一度アディショナルベクターされたやつは消されている。get_vecでベクトルとって、それを内積取るためのset_calc_dot_product_withに入れてる。で、フォワードパスのたびにこのベクトルとの内積が計算されリストにためられる。何と内積を取るかといえばdecodeフェーズで毎回吐くトークンがlast_token_activationsで取れるのでそれと内積取ってる
code:py
def forward(self, *args, **kwargs):
output = self.block(*args, **kwargs)
self.activations = output0 if self.calc_dot_product_with is not None:
last_token_activations = self.activations0, -1, : decoded_activations = self.unembed_matrix(self.norm(last_token_activations))
top_token_id = torch.topk(decoded_activations, 1)10 top_token = self.tokenizer.decode(top_token_id)
dot_product = torch.dot(last_token_activations, self.calc_dot_product_with)
self.dot_products.append((top_token, dot_product.cpu().item()))
https://scrapbox.io/files/673ad7d2b5e5308525aaf583.png
トランスフォーマー モデルに関する興味深い事実は、残差ストリームの任意のレイヤーについて、アクティベーションの平均が非常に大きく、決して 0 ではないということです。
https://scrapbox.io/files/67398df624c0df09a24cd103.png
私は基本的に、平均中心化が特徴ベクトルを抽出する最も原理的な方法であると証拠なしに主張するつもりです。
どうやって達成するか?といえばセンターベクトルを基準に考えれば良い
https://scrapbox.io/files/67398f5ddc8eb00671c32d7c.png
この構造になっているので引き算するとlove-hateが取り出せるんやでの話
Steering Vectorをやったというよりもどんだけごますりしてくるかの話
★中間のデコード。コードあり
迷路解く問題とかもおもろい