mcpField
P
pyvene-interventions

pyvene-interventions

github.com/orchestra-researchデータ・データベース14.1k960 回インストール19 週間前に更新
リポジトリ

pyvene-interventions について

pyvene-interventionsは、pyveneを使ってPyTorchモデルに因果介入する方法を扱うスキルです。モデル解釈性の研究者向けに、活性パッチング、因果トレース、介入学習の宣言的な設定と、介入の保存・共有を解説します。

主な機能

  1. 01宣言的な介入設定
  2. 02活性の交換・加算・ゼロ化
  3. 03因果トレースと活性パッチング
  4. 04学習可能な介入とモデル操舵
  5. 05介入の保存と共有

活用シーン

  1. 01事実関連がモデル内に保存された位置を特定
  2. 02モデルの振る舞いに関わる構成要素を分析
  3. 03因果構造を調べる介入を学習

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/orchestra-research/ai-research-skills --skill pyvene-interventions

インストール後、Claude Code で/pyvene-interventionsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api.md
README.md
tutorials.md

詳細

pyvene: ニューラルネットワークのための因果的介入

pyvene は Stanford NLP による、PyTorch モデルに対して因果的介入を行うためのライブラリです。活性化パッチング、因果トレーシング、交換介入(interchange intervention)トレーニングのための宣言的な dict ベースのフレームワークを提供し、介入実験を再現可能かつ共有可能にします。

GitHub: stanfordnlp/pyvene(840+ スター) 論文: pyvene: A Library for Understanding and Improving PyTorch Models via Interventions(NAACL 2024)

pyvene を使うべき場合

次のことが必要な場合は pyvene を使用してください:

  • 因果トレーシング(ROME 方式の局在化)を行う
  • 活性化パッチング実験を実行する
  • 交換介入トレーニング(IIT)を行う
  • モデルのコンポーネントに関する因果仮説を検証する
  • HuggingFace を介して介入実験を共有・再現する
  • 任意の PyTorch アーキテクチャで作業する(transformers に限らない)

次の場合は代替手段を検討してください:

  • 探索的な活性化分析が必要 → TransformerLens を使用
  • SAE の学習・分析を行いたい → SAELens を使用
  • 大規模モデルでリモート実行が必要 → nnsight を使用
  • より低レベルな制御が欲しい → nnsight を使用

インストール

pip install pyvene

標準的なインポート:

import pyvene as pv

中核となる概念

IntervenableModel

任意の PyTorch モデルを介入機能でラップする主要なクラスです:

import pyvene as pv
from transformers import AutoModelForCausalLM, AutoTokenizer

# Load base model
model = AutoModelForCausalLM.from_pretrained("gpt2")
tokenizer = AutoTokenizer.from_pretrained("gpt2")

# Define intervention configuration
config = pv.IntervenableConfig(
    representations=[
        pv.RepresentationConfig(
            layer=8,
            component="block_output",
            intervention_type=pv.VanillaIntervention,
        )
    ]
)

# Create intervenable model
intervenable = pv.IntervenableModel(config, model)
介入の種類
種類説明用途
VanillaIntervention実行間で活性化を入れ替える活性化パッチング
AdditionInterventionベースの実行に活性化を加算するステアリング、アブレーション
SubtractionIntervention活性化を減算するアブレーション
ZeroIntervention活性化をゼロにするコンポーネントのノックアウト
RotatedSpaceIntervention学習可能な DAS 介入因果発見
CollectIntervention活性化を収集するプロービング、分析
コンポーネントのターゲット
# Available components to intervene on
components = [
    "block_input",      # Input to transformer block
    "block_output",     # Output of transformer block
    "mlp_input",        # Input to MLP
    "mlp_output",       # Output of MLP
    "mlp_activation",   # MLP hidden activations
    "attention_input",  # Input to attention
    "attention_output", # Output of attention
    "attention_value_output",  # Attention value vectors
    "query_output",     # Query vectors
    "key_output",       # Key vectors
    "value_output",     # Value vectors
    "head_attention_value_output",  # Per-head values
]

ワークフロー 1: 因果トレーシング(ROME 方式)

入力を破壊し、活性化を復元することで、事実的な関連情報がどこに保存されているかを特定します。

ステップごとの手順
import pyvene as pv
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model = AutoModelForCausalLM.from_pretrained("gpt2-xl")
tokenizer = AutoTokenizer.from_pretrained("gpt2-xl")

# 1. Define clean and corrupted inputs
clean_prompt = "The Space Needle is in downtown"
corrupted_prompt = "The ##### ###### ## ## ########"  # Noise

clean_tokens = tokenizer(clean_prompt, return_tensors="pt")
corrupted_tokens = tokenizer(corrupted_prompt, return_tensors="pt")

# 2. Get clean activations (source)
with torch.no_grad():
    clean_outputs = model(**clean_tokens, output_hidden_states=True)
    clean_states = clean_outputs.hidden_states

# 3. Define restoration intervention
def run_causal_trace(layer, position):
    """Restore clean activation at specific layer and position."""
    config = pv.IntervenableConfig(
        representations=[
            pv.RepresentationConfig(
                layer=layer,
                component="block_output",
                intervention_type=pv.VanillaIntervention,
                unit="pos",
                max_number_of_units=1,
            )
        ]
    )

    intervenable = pv.IntervenableModel(config, model)

    # Run with intervention
    _, patched_outputs = intervenable(
        base=corrupted_tokens,
        sources=[clean_tokens],
        unit_locations={"sources->base": ([[[position]]], [[[position]]])},
        output_original_output=True,
    )

    # Return probability of correct token
    probs = torch.softmax(patched_outputs.logits[0, -1], dim=-1)
    seattle_token = tokenizer.encode(" Seattle")[0]
    return probs[seattle_token].item()

# 4. Sweep over layers and positions
n_layers = model.config.n_layer
seq_len = clean_tokens["input_ids"].shape[1]

results = torch.zeros(n_layers, seq_len)
for layer in range(n_layers):
    for pos in range(seq_len):
        results[layer, pos] = run_causal_trace(layer, pos)

# 5. Visualize (layer x position heatmap)
# High values indicate causal importance
チェックリスト
  • 対象となる事実的関連を含むクリーンなプロンプトを用意する
  • 破壊されたバージョン(ノイズまたは反事実)を作成する
  • 各 (layer, position) に対する介入設定を定義する
  • パッチングのスイープを実行する
  • ヒートマップで因果的ホットスポットを特定する

ワークフロー 2: 回路分析のための活性化パッチング

特定の振る舞いに必要なコンポーネントを検証します。

ステップごとの手順
import pyvene as pv
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model = AutoModelForCausalLM.from_pretrained("gpt2")
tokenizer = AutoTokenizer.from_pretrained("gpt2")

# IOI task setup
clean_prompt = "When John and Mary went to the store, Mary gave a bottle to"
corrupted_prompt = "When John and Mary went to the store, John gave a bottle to"

clean_tokens = tokenizer(clean_prompt, return_tensors="pt")
corrupted_tokens = tokenizer(corrupted_prompt, return_tensors="pt")

john_token = tokenizer.encode(" John")[0]
mary_token = tokenizer.encode(" Mary")[0]

def logit_diff(logits):
    """IO - S logit difference."""
    return logits[0, -1, john_token] - logits[0, -1, mary_token]

# Patch attention output at each layer
def patch_attention(layer):
    config = pv.IntervenableConfig(
        representations=[
            pv.RepresentationConfig(
                layer=layer,
                component="attention_output",
                intervention_type=pv.VanillaIntervention,
            )
        ]
    )

    intervenable = pv.IntervenableModel(config, model)

    _, patched_outputs = intervenable(
        base=corrupted_tokens,
        sources=[clean_tokens],
    )

    return logit_diff(patched_outputs.logits).item()

# Find which layers matter
results = []
for layer in range(model.config.n_layer):
    diff = patch_attention(layer)
    results.append(diff)
    print(f"Layer {layer}: logit diff = {diff:.3f}")

ワークフロー 3: 交換介入トレーニング(IIT)

因果構造を発見するために介入を学習させます。

ステップごとの手順
import pyvene as pv
from transformers import AutoModelForCausalLM
import torch

model = AutoModelForCausalLM.from_pretrained("gpt2")

# 1. Define trainable intervention
config = pv.IntervenableConfig(
    representations=[
        pv.RepresentationConfig(
            layer=6,
            component="block_output",
            intervention_type=pv.RotatedSpaceIntervention,  # Trainable
            low_rank_dimension=64,  # Learn 64-dim subspace
        )
    ]
)

intervenable = pv.IntervenableModel(config, model)

# 2. Set up training
optimizer = torch.optim.Adam(
    intervenable.get_trainable_parameters(),
    lr=1e-4
)

# 3. Training loop (simplified)
for base_input, source_input, target_output in dataloader:
    optimizer.zero_grad()

    _, outputs = intervenable(
        base=base_input,
        sources=[source_input],
    )

    loss = criterion(outputs.logits, target_output)
    loss.backward()
    optimizer.step()

# 4. Analyze learned intervention
# The rotation matrix reveals causal subspace
rotation = intervenable.interventions["layer.6.block_output"][0].rotate_layer
DAS(Distributed Alignment Search)
# Low-rank rotation finds interpretable subspaces
config = pv.IntervenableConfig(
    representations=[
        pv.RepresentationConfig(
            layer=8,
            component="block_output",
            intervention_type=pv.LowRankRotatedSpaceIntervention,
            low_rank_dimension=1,  # Find 1D causal direction
        )
    ]
)

ワークフロー 4: モデルのステアリング(Honest LLaMA)

生成時にモデルの振る舞いを制御します。

import pyvene as pv
from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")

# Load pre-trained steering intervention
intervenable = pv.IntervenableModel.load(
    "zhengxuanzenwu/intervenable_honest_llama2_chat_7B",
    model=model,
)

# Generate with steering
prompt = "Is the earth flat?"
inputs = tokenizer(prompt, return_tensors="pt")

# Intervention applied during generation
outputs = intervenable.generate(
    inputs,
    max_new_tokens=100,
    do_sample=False,
)

print(tokenizer.decode(outputs[0]))

介入の保存と共有

# Save locally
intervenable.save("./my_intervention")

# Load from local
intervenable = pv.IntervenableModel.load(
    "./my_intervention",
    model=model,
)

# Share on HuggingFace
intervenable.save_intervention("username/my-intervention")

# Load from HuggingFace
intervenable = pv.IntervenableModel.load(
    "username/my-intervention",
    model=model,
)

よくある問題と解決策

問題: 介入位置が誤っている
# WRONG: Incorrect component name
config = pv.RepresentationConfig(
    component="mlp",  # Not valid!
)

# RIGHT: Use exact component name
config = pv.RepresentationConfig(
    component="mlp_output",  # Valid
)
問題: 次元の不一致
# Ensure source and base have compatible shapes
# For position-specific interventions:
config = pv.RepresentationConfig(
    unit="pos",
    max_number_of_units=1,  # Intervene on single position
)

# Specify locations explicitly
intervenable(
    base=base_tokens,
    sources=[source_tokens],
    unit_locations={"sources->base": ([[[5]]], [[[5]]])},  # Position 5
)
問題: 大規模モデルでのメモリ
# Use gradient checkpointing
model.gradient_checkpointing_enable()

# Or intervene on fewer components
config = pv.IntervenableConfig(
    representations=[
        pv.RepresentationConfig(
            layer=8,  # Single layer instead of all
            component="block_output",
        )
    ]
)
問題: LoRA との統合
# pyvene v0.1.8+ supports LoRAs as interventions
config = pv.RepresentationConfig(
    intervention_type=pv.LoRAIntervention,
    low_rank_dimension=16,
)

主要クラスのリファレンス

クラス用途
IntervenableModel介入のためのメインのラッパー
IntervenableConfig設定のコンテナ
RepresentationConfig単一の介入仕様
VanillaIntervention活性化の入れ替え
RotatedSpaceIntervention学習可能な DAS 介入
CollectIntervention活性化の収集

対応モデル

pyvene は任意の PyTorch モデルで動作します。以下でテストされています:

  • GPT-2(すべてのサイズ)
  • LLaMA / LLaMA-2
  • Pythia
  • Mistral / Mixtral
  • OPT
  • BLIP(視覚言語)
  • ESM(タンパク質モデル)
  • Mamba(状態空間モデル)

リファレンスドキュメント

詳細な API ドキュメント、チュートリアル、高度な使い方については、references/ フォルダーを参照してください。

ファイル内容
references/README.md概要とクイックスタートガイド
references/api.mdIntervenableModel、介入タイプ、設定に関する完全な API リファレンス
references/tutorials.md因果トレーシング、アクティベーションパッチング、DAS のステップバイステップのチュートリアル

外部リソース

チュートリアル
論文
公式ドキュメント

他のツールとの比較

機能pyveneTransformerLensnnsight
宣言的な設定YesNoNo
HuggingFace での共有YesNoNo
学習可能な介入YesLimitedYes
任意の PyTorch モデルYesTransformers onlyYes
リモート実行NoNoYes (NDIF)

コメント