mcpField
T
transformer-lens-interpretability

transformer-lens-interpretability

github.com/orchestra-research数据与数据库14.1k962 次安装19 周前更新
代码仓库

关于 transformer-lens-interpretability

TransformerLens 是面向研究者的 Python 库,用于研究 GPT 风格语言模型的内部机制。它通过激活值上的 HookPoint 支持检查、干预和电路分析。

主要功能

  1. 01模型激活值钩子
  2. 02缓存中间激活值
  3. 03激活值修补与因果追踪
  4. 04注意力与电路分析
  5. 05直接 Logit 归因

适用场景

  1. 01追踪影响模型输出的激活值
  2. 02检查注意力模式与信息流
  3. 03分析归纳头和 IOI 电路

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/orchestra-research/ai-research-skills --skill transformer-lens-interpretability

安装后在 Claude Code 中输入/transformer-lens-interpretability确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api.md
README.md
tutorials.md

详细介绍

TransformerLens:面向 Transformer 的机制可解释性

TransformerLens 是 GPT 风格语言模型机制可解释性研究事实上的标准库。它由 Neel Nanda 创建、Bryce Meyer 维护,通过每个激活值上的 HookPoint 提供简洁的接口来检查和操控模型内部。

GitHub:TransformerLensOrg/TransformerLens(2,900+ stars)

何时使用 TransformerLens

在以下情况下使用 TransformerLens:

  • 逆向工程训练期间学到的算法
  • 执行激活值修补 / 因果追踪实验
  • 研究注意力模式和信息流
  • 分析回路(例如 induction heads、IOI 回路)
  • 缓存并检查中间激活值
  • 应用直接 logit 归因

在以下情况下考虑替代方案:

  • 你需要处理非 transformer 架构 → 使用 nnsight 或 pyvene
  • 你想训练/分析稀疏自编码器 → 使用 SAELens
  • 你需要在超大模型上进行远程执行 → 使用带 NDIF 的 nnsight
  • 你想要更高层次的因果干预抽象 → 使用 pyvene

安装

pip install transformer-lens

开发版本:

pip install git+https://github.com/TransformerLensOrg/TransformerLens

核心概念

HookedTransformer

主类,它将 transformer 模型包装起来,并在每个激活值上提供 HookPoint:

from transformer_lens import HookedTransformer

# Load a model
model = HookedTransformer.from_pretrained("gpt2-small")

# For gated models (LLaMA, Mistral)
import os
os.environ["HF_TOKEN"] = "your_token"
model = HookedTransformer.from_pretrained("meta-llama/Llama-2-7b-hf")
支持的模型(50+)
系列模型
GPT-2gpt2, gpt2-medium, gpt2-large, gpt2-xl
LLaMAllama-7b, llama-13b, llama-2-7b, llama-2-13b
EleutherAIpythia-70m 到 pythia-12b, gpt-neo, gpt-j-6b
Mistralmistral-7b, mixtral-8x7b
其他phi, qwen, opt, gemma
激活值缓存

运行模型并缓存所有中间激活值:

# Get all activations
tokens = model.to_tokens("The Eiffel Tower is in")
logits, cache = model.run_with_cache(tokens)

# Access specific activations
residual = cache["resid_post", 5]  # Layer 5 residual stream
attn_pattern = cache["pattern", 3]  # Layer 3 attention pattern
mlp_out = cache["mlp_out", 7]  # Layer 7 MLP output

# Filter which activations to cache (saves memory)
logits, cache = model.run_with_cache(
    tokens,
    names_filter=lambda name: "resid_post" in name
)
ActivationCache 键
键模式形状描述
resid_pre, layer[batch, pos, d_model]注意力之前的残差
resid_mid, layer[batch, pos, d_model]注意力之后的残差
resid_post, layer[batch, pos, d_model]MLP 之后的残差
attn_out, layer[batch, pos, d_model]注意力输出
mlp_out, layer[batch, pos, d_model]MLP 输出
pattern, layer[batch, head, q_pos, k_pos]注意力模式(softmax 后)
q, layer[batch, pos, head, d_head]查询向量
k, layer[batch, pos, head, d_head]键向量
v, layer[batch, pos, head, d_head]值向量

工作流 1:激活值修补(因果追踪)

通过将干净激活值修补到损坏的运行中,识别哪些激活值对模型输出有因果影响。

分步操作
from transformer_lens import HookedTransformer, patching
import torch

model = HookedTransformer.from_pretrained("gpt2-small")

# 1. Define clean and corrupted prompts
clean_prompt = "The Eiffel Tower is in the city of"
corrupted_prompt = "The Colosseum is in the city of"

clean_tokens = model.to_tokens(clean_prompt)
corrupted_tokens = model.to_tokens(corrupted_prompt)

# 2. Get clean activations
_, clean_cache = model.run_with_cache(clean_tokens)

# 3. Define metric (e.g., logit difference)
paris_token = model.to_single_token(" Paris")
rome_token = model.to_single_token(" Rome")

def metric(logits):
    return logits[0, -1, paris_token] - logits[0, -1, rome_token]

# 4. Patch each position and layer
results = torch.zeros(model.cfg.n_layers, clean_tokens.shape[1])

for layer in range(model.cfg.n_layers):
    for pos in range(clean_tokens.shape[1]):
        def patch_hook(activation, hook):
            activation[0, pos] = clean_cache[hook.name][0, pos]
            return activation

        patched_logits = model.run_with_hooks(
            corrupted_tokens,
            fwd_hooks=[(f"blocks.{layer}.hook_resid_post", patch_hook)]
        )
        results[layer, pos] = metric(patched_logits)

# 5. Visualize results (layer x position heatmap)
检查清单
  • 定义差异最小的干净输入和损坏输入
  • 选择能捕捉行为差异的指标
  • 缓存干净激活值
  • 系统性地修补每个 (layer, position) 组合
  • 将结果可视化为热力图
  • 识别因果热点

工作流 2:回路分析(间接宾语识别)

复现 "Interpretability in the Wild" 中的 IOI 回路发现。

分步操作
from transformer_lens import HookedTransformer
import torch

model = HookedTransformer.from_pretrained("gpt2-small")

# IOI task: "When John and Mary went to the store, Mary gave a bottle to"
# Model should predict "John" (indirect object)

prompt = "When John and Mary went to the store, Mary gave a bottle to"
tokens = model.to_tokens(prompt)

# 1. Get baseline logits
logits, cache = model.run_with_cache(tokens)

john_token = model.to_single_token(" John")
mary_token = model.to_single_token(" Mary")

# 2. Compute logit difference (IO - S)
logit_diff = logits[0, -1, john_token] - logits[0, -1, mary_token]
print(f"Logit difference: {logit_diff.item():.3f}")

# 3. Direct logit attribution by head
def get_head_contribution(layer, head):
    # Project head output to logits
    head_out = cache["z", layer][0, :, head, :]  # [pos, d_head]
    W_O = model.W_O[layer, head]  # [d_head, d_model]
    W_U = model.W_U  # [d_model, vocab]

    # Head contribution to logits at final position
    contribution = head_out[-1] @ W_O @ W_U
    return contribution[john_token] - contribution[mary_token]

# 4. Map all heads
head_contributions = torch.zeros(model.cfg.n_layers, model.cfg.n_heads)
for layer in range(model.cfg.n_layers):
    for head in range(model.cfg.n_heads):
        head_contributions[layer, head] = get_head_contribution(layer, head)

# 5. Identify top contributing heads (name movers, backup name movers)
检查清单
  • 设置具有清晰 IO/S token 的任务
  • 计算基线 logit 差值
  • 按注意力头贡献进行分解
  • 识别关键回路组件(name movers、S-inhibition、induction)
  • 通过消融实验进行验证

工作流 3:Induction Head 检测

查找实现 [A][B]...[A] → [B] 模式的 induction heads。

from transformer_lens import HookedTransformer
import torch

model = HookedTransformer.from_pretrained("gpt2-small")

# Create repeated sequence: [A][B][A] should predict [B]
repeated_tokens = torch.tensor([[1000, 2000, 1000]])  # Arbitrary tokens

_, cache = model.run_with_cache(repeated_tokens)

# Induction heads attend from final [A] back to first [B]
# Check attention from position 2 to position 1
induction_scores = torch.zeros(model.cfg.n_layers, model.cfg.n_heads)

for layer in range(model.cfg.n_layers):
    pattern = cache["pattern", layer][0]  # [head, q_pos, k_pos]
    # Attention from pos 2 to pos 1
    induction_scores[layer] = pattern[:, 2, 1]

# Heads with high scores are induction heads
top_heads = torch.topk(induction_scores.flatten(), k=5)

常见问题与解决方案

问题:调试后 Hook 仍然存在
# WRONG: Old hooks remain active
model.run_with_hooks(tokens, fwd_hooks=[...])  # Debug, add new hooks
model.run_with_hooks(tokens, fwd_hooks=[...])  # Old hooks still there!

# RIGHT: Always reset hooks
model.reset_hooks()
model.run_with_hooks(tokens, fwd_hooks=[...])
问题:分词陷阱
# WRONG: Assuming consistent tokenization
model.to_tokens("Tim")  # Single token
model.to_tokens("Neel")  # Becomes "Ne" + "el" (two tokens!)

# RIGHT: Check tokenization explicitly
tokens = model.to_tokens("Neel", prepend_bos=False)
print(model.to_str_tokens(tokens))  # ['Ne', 'el']
问题:分析中忽略 LayerNorm
# WRONG: Ignoring LayerNorm
pre_activation = residual @ model.W_in[layer]

# RIGHT: Include LayerNorm
ln_scale = model.blocks[layer].ln2.w
ln_out = model.blocks[layer].ln2(residual)
pre_activation = ln_out @ model.W_in[layer]
问题:大模型导致内存爆炸
# Use selective caching
logits, cache = model.run_with_cache(
    tokens,
    names_filter=lambda n: "resid_post" in n or "pattern" in n,
    device="cpu"  # Cache on CPU
)

关键类参考

类用途
HookedTransformer带钩子的主模型封装
ActivationCache类似字典的激活缓存
HookedTransformerConfig模型配置
FactoredMatrix高效的因子化矩阵运算

与 SAELens 的集成

TransformerLens 与 SAELens 集成,用于稀疏自编码器分析:

from transformer_lens import HookedTransformer
from sae_lens import SAE

model = HookedTransformer.from_pretrained("gpt2-small")
sae = SAE.from_pretrained("gpt2-small-res-jb", "blocks.8.hook_resid_pre")

# Run with SAE
tokens = model.to_tokens("Hello world")
_, cache = model.run_with_cache(tokens)
sae_acts = sae.encode(cache["resid_pre", 8])

参考文档

有关详细的 API 文档、教程和高级用法,请参阅 references/ 文件夹:

文件内容
references/README.md概述和快速入门指南
references/api.mdHookedTransformer、ActivationCache、HookPoints 的完整 API 参考
references/tutorials.md激活补丁、电路分析、logit lens 的分步教程

外部资源

教程
论文
官方文档

版本说明

  • v2.0:移除了 HookedSAE(已迁移至 SAELens)
  • v3.0 (alpha):TransformerBridge 用于加载任意 nn.Module

评论

支持 Markdown