1024 特刊|用稀疏自编码器拆开激活:重构得好,为什么仍不能直接叫“找到知识”

发布时间:2026/10/25 9:23:31
1024 特刊|用稀疏自编码器拆开激活:重构得好,为什么仍不能直接叫“找到知识”

一个特征在“巴黎”“法国”等文本上亮起来,看上去很像地理知识节点。但解释性标签来自观察,因果作用需要干预,两者不能省略中间证据。

2024 年的 TopK SAE 研究讨论了如何直接控制稀疏度及评估特征质量;同年的 JumpReLU 论文提出另一种稀疏激活方式。这些工作不是“所有模型已经统一采用 TopK”的证据。10 月数学成果公开后,对推理机制的解释需求更强,但成绩本身不会告诉我们内部哪条回路负责推导。

三件容易混在一起的事

SAE 把模型激活 x 编码为稀疏向量 z,再解码为重构激活 x_hat。常见损失包含重构误差,并用显式稀疏约束或惩罚控制激活数量。重构质量回答的是“还原了多少输入信息”,并不自动回答“每个方向是否对应人类概念”。

图中重构向量与原向量外观相同只是理想化示意,真实 SAE 通常有重构误差。完整实验还要把重构激活替换回原模型,测下游损失或任务行为是否变化。

一个不训练模型的稀疏瓶颈

先用单位字典把最基本的选择过程跑通。下面保留最大的 k 个正激活,其他位置归零。单位字典只是为了让结果可以手算;真实 SAE 的字典需要学习,维数往往也不同。

def topk_relu(values, k): if not 0 < k <= len(values): raise ValueError("invalid k") positive = [max(0.0, float(value)) for value in values] selected = sorted(range(len(values)), key=lambda index: positive[index], reverse=True)[:k] output = [0.0] * len(values) for index in selected: output[index] = positive[index] return output def mse(left, right): if len(left) != len(right) or not left: raise ValueError("same nonempty shape required") return sum((a - b) ** 2 for a, b in zip(left, right)) / len(left) x = [2.0, -1.0, 0.5, 0.0] z = topk_relu(x, 2) x_hat = list(z) # identity decoder, deliberately not a learned SAE assert z == [2.0, 0.0, 0.5, 0.0] assert mse(x, x_hat) == 0.25 assert sum(value != 0 for value in z) <= 2 print("sparse:", z, "reconstruction_mse:", mse(x, x_hat))

这里负分量被 ReLU 丢掉,误差恰好是 0.25。把 k 改大也无法恢复该负分量。这说明稀疏度、激活函数和字典表达能力会共同限制重构;不能把误差变化全归因于“语义纯度”。

从可视化走到可反驳实验

如果给某个特征贴上“拒答”或“城市”标签,下一步应准备正例、反例和容易混淆的对照。既看最高激活样本,也看低激活但应包含概念的样本,避免只挑漂亮截图。

做因果干预时,再比较关掉特征、放大特征、随机方向干预,以及用 SAE 重构整体替换激活的结果。只关闭某方向就改变回答,也可能源于破坏了大量混合信息。要说明干预强度、层、token 位置和副作用。

“一个 batch 没出现”也不是长期死特征。死特征统计需要定义观察窗口;否则稀有但有效的方向会被误判。本文例子没有 Ghost Gradients、辅助损失或大模型训练,不以几十行代码声称具备这些能力。它只验证稀疏选择与重构误差,真实特征语义、下游保真度和因果解释均未测。