🔬 SAE 特征索引到语义的对应机制
核心问题
SAE(稀疏自编码器)产生的特征索引(0-32767)只是一个数字,
如何知道它代表什么语义?
答案:SAE 特征没有预定义的语义标签!
语义不是"查找"出来的,而是通过实验"发现"的。
📊 四种发现语义的方法
1激活模式分析
Activation Patterns / Top Activations
观察"哪些 token 激活了这个特征",推断其语义
最常用
2特征比较
Feature Comparison
对比两段文本的激活差异,找出显著不同的特征
对比分析
3Steering 干预
Causal Intervention
增强/抑制特征,观察模型输出变化
最强验证
4自动化命名
Automated Naming
用 LLM 总结 Top Activations,自动命名特征
领域通用
🔥 方法一:激活模式分析(热力图)
原理
每个 SAE 特征在特定输入上会被激活。通过观察"哪些 token 激活了这个特征",可以推断其语义。
代码实现
def feature_heatmap_to_html(tokens, features, top_k, skip_first):
seq_len, sae_width = features.shape
mean_activation = features.mean(dim=0)
topk_indices = mean_activation.topk(top_k).indices
for feat_idx in topk_indices:
row_activations = features[:, feat_idx]
示例:特征 #1234 的激活热力图
特征 #1234
0.1
0.3
0.2
0.9
0.1
0.85
→ 该特征在 "China" 和 "Beijing" 上激活最强 → 推断:可能表示"中国相关概念"
⚖️ 方法二:特征比较
原理
比较两段文本的 SAE 激活差异,找出在一段文本中激活强、另一段中激活弱的特征。
示例
文本1
"我喜欢编程,写代码很有趣"
文本2
"我喜欢游泳,运动很健康"
| 特征索引 | 文本1 激活 | 文本2 激活 | 差异 | 推断语义 |
| #5678 | 0.85 | 0.12 | +0.73 | 可能与"编程"相关 |
| #9012 | 0.10 | 0.78 | -0.68 | 可能与"运动"相关 |
| #3456 | 0.65 | 0.62 | +0.03 | 通用概念(如"喜欢") |
🎯 方法三:Steering 干预(因果验证)
原理
这是最强的语义验证方法。人为增强或抑制某个特征的激活,观察模型输出变化。
数学本质
hidden_new = hidden_old + strength × W_dec[feat_idx]
代码实现
def _steer_hook(module, inp, out):
hidden = out[0].clone()
hidden[:, pos, :] += strength * sae['W_dec'][feat_idx]
return (hidden,) + out[1:]
示例
原始
Prompt: "The capital of France is"
输出: "Paris"
增强特征 #1234 后
Prompt: "The capital of France is"
输出: "Beijing" 或中国相关内容
→ 确认特征 #1234 与"中国"语义相关
🤖 方法四:自动化命名
⚠️ Qwen-Scope 本身未实现此功能,但这是 SAE 解释领域的通用方法。
标准流程
① 在大规模语料库上运行模型,收集每个特征的 Top Activations
↓
② 对每个特征,收集激活最强的 100-1000 个 token/句子
↓
③ 用 LLM 自动命名:"这个特征在以下文本上激活最强:[列表],请给它一个语义名称"
↓
④ 人工审核命名结果
示例
"dog" (0.92), "cat" (0.89), "pet" (0.85), "animal" (0.82), "fish" (0.78)...
📋 完整工作流程
Step 1: 选择特征索引(如 #12345)
↓
Step 2: 激活模式分析 → 什么文本触发了它?
↓
Step 3: 特征比较 → 它在什么场景下激活更强?
↓
Step 4: Steering 干预 → 增强/抑制它,模型行为如何变化?
↓
Step 5: 语义命名 → 用自然语言描述该特征的语义
📁 关键代码位置索引
| 功能 | 函数名 | 行号 | 说明 |
| SAE 特征计算 | compute_sae_features | 252-265 | 隐藏状态 → SAE 特征 |
| 热力图生成 | feature_heatmap_to_html | 295-413 | 特征×Token 激活热力图 |
| 特征分析回调 | cb_analyze | 506-517 | 入口:分析文本的特征激活 |
| Steering 强度 | _steering_strength_from_mode | 521-545 | 映射 Light/Medium/Strong |
| Steering Hook | _steer_hook | ~820 | 修改隐藏状态注入特征 |
| 特征比较 | cb_compare | 1082+ | 对比两段文本的特征差异 |
| 比较结果渲染 | compare_to_html | 859+ | 渲染差异特征表 |
💡 类比理解
SAE 特征索引到语义的对应,就像化学中发现新元素——你不能查字典知道元素 118 的性质,你需要通过实验来发现它。
特征索引 #12345 本身只是一个数字,它的语义由它在什么输入上激活以及它对模型输出有什么影响来定义。
基于 Qwen-Scope 源代码分析 | SAE 特征解释机制研究