Interpretability / From pixels and words to sparse features

Lesson 1: MLLM-SAE

以 Qwen3.5-9B 与 Gemma 4 E4B 为例,沿着图片、问题和答案追踪 hidden state,走完多模态 SAE 的数据、hook、训练与特征使用流程。

本课要训练的是一个读取冻结模型内部表示的 SAE。图片、问题和已有答案先经过 MLLM;SAE 学习重构其中一个位置的 hidden state,并把它表示成少量 feature 的组合。下面的交互图是可操作的教学模拟,feature 编号、名称与激活值均不是实测结果。

本课以 Qwen/Qwen3.5-9B 和 google/gemma-4-E4B-it 为例,目标是为图文指令数据建立可解释的去重与覆盖指纹。先回答最关键的问题:一个模型、一个 hook、一个共同训练的 SAE,可以让图片位置和文本位置共用一个 65,536 维字典;两个模型不能共用同一个 SAE。字典也没有预先划分“图片区”和“文本区”。

模型与实现核对日期:2026-11-06。E4B 的模型链接是 google/gemma-4-E4B-it,不是 E2B。Qwen 家族的 GitHub 地址虽然已经指向 Qwen3.8,本课固定使用 Qwen3.5-9B checkpoint。本文的层位、数据配比与验收门槛是待验证的实验起点,没有论文证明它们在这两个模型上最优。

01 · 跟随一张图片,走进模型

图中用一张包含两个红苹果、一个杯子和 SALE 字牌的教学插画,配合问题与答案。切换模型、hook 或 token 来源,观察张量形状与 SAE 输入如何改变;点击“播放一次”沿着前向计算逐步查看。图片不会经过文本 tokenizer;进入语言主干的是视觉编码后的向量,占据序列中的图片位置。

FIGURE 01 · TRACE A SAMPLE从像素到稀疏特征切换一个条件,看表示如何改变
两个苹果、杯子与 SALE 字牌;教学插画SALE教学插画 · 512 × 512 正方形输入
USER · QWhat color are the apples?
ASSISTANT · AnsThe apples are red.
图在前、问在后;答案由已有训练数据提供
冻结 MLLM · 图片路线 →
文本旁路 ↗Q / Ans → tokenizer → embed_tokens → [1, N_text, 4096] → 融合进 LLM
主模型继续向前 →其余 blocks → norm → LM head → logits [1, L, 248320] → 下一 token
↓ 从 C 输出复制并 detach · 主模型继续使用原 hidden
SAE 读取分支model.language_model.layers.23[N, 4096]选择有效位置 → 固定 μ/s
01 / 06把图片放在问题前面,已有答案在后面。teacher forcing 不执行自由生成,也不更新原模型。
从 LLM 选位置模板 ×padding ×
C HOOK · 问题 Qmodel.language_model.layers.23

带图片上下文的颜色查询;可含任务意图与视觉关联。

选择并 detach[N, 4096]h → 固定 μ/s → x
encoder + TopK[N, 65,536]z:每行最多 64 个非零
decoder 重构[N, 4096]x̂ → 还原 ĥ
希望检验的 feature:颜色查询提问句式图文关联候选

尺寸来自配置;feature 标签为教学假设。I/Q/Ans 共用本模型这个 hook 的 65K 字典。 其他模型、层位和 hook 不共用 feature ID。

主实验选 C:语言主干完整 block 的输出。这个位置保留了残差流中的综合信息,适合同时研究视觉内容、提问方式与答案信息。选择它是因为研究目标是整条图文指令的数据选择,而不是单独解释某个 attention 或 MLP 分支。

三种 hook,各自回答不同问题

这里的路径相对于 Hugging Face 的完整 ForConditionalGeneration 对象,层号均从 0 开始。config 给出尺寸与层数;模块路径要结合实现源码确认,启动时再用 named_modules() 和一次前向校验。以下形状来自配置与源码推导,本文没有运行这两个模型的权重。Qwen 配置 · Gemma 配置 · Qwen 实现 · Gemma 实现

位置与目的 Qwen3.5-9B:模块输出 Gemma 4 E4B:模块输出 SAE 想发现什么?
A · 视觉编码器末层,pool/merge 之前 model.visual.blocks.26 → [N_patch, 1152] model.vision_tower.encoder.layers.15 → [B_img, P_max, 768],先去掉 padding patch 物体、颜色、纹理、区域及视觉语义;保留较细的空间位置。它没有读取问题。可选独立 16K 字典。
B · 视觉桥接之后,进入 LLM 之前 model.visual.merger → [N_visual, 4096] model.embed_vision → [N_visual, 2560],前面已经完成视觉 pooling 与去 padding 空间压缩后、适配语言主干的视觉信息。它仍没有读取问题。可选独立 32K 字典。
C · 主配置:完整语言 block 输出 model.language_model.layers.23 → [B, L, 4096] model.language_model.layers.29 → [B, L, 2560] 从图片 I、问题 Q、答案 Ans 位置分别采样;期待得到视觉偏好、语言偏好、任务相关或跨模态 feature。每个模型独立训练一个 65,536 维字典。
层位对照 独立比较 layers.15 / 23 / 27 独立比较 layers.23 / 29 / 35 固定数据、预算、字典宽度与稀疏度;用去重误删率、覆盖和下游 SFT 选择,不凭“越深越好”判断。
最后归一化输出:额外对照 model.language_model.norm → [B,L,4096] model.language_model.norm → [B,L,2560] 预测输出前的表示,分布与中间残差不同,需要另训 SAE 与归一化统计。

“完整 block 输出”不等于 mlp.down_proj 输出。 Qwen 的 block 输出已经加回 residual;Gemma 还包含 MLP 后归一化、每层输入分支(PLE)与 layer scalar。若 hook 在 down_proj 或 self_attn.o_proj,得到的只是分支贡献,不能沿用 C 的解释与统计。

两个主干的差异,为什么会影响 hook

配置 Qwen3.5-9B Gemma 4 E4B
视觉编码器 27 blocks,hidden = 1,152,patch = 16 16 layers,hidden = 768,patch = 16
视觉压缩 2×2 patches 合并,再映射到 4,096;本 checkpoint 无 DeepStack 3×3 空间 pooling,去 padding,再归一化投影到 2,560
语言主干 32 blocks,hidden = 4,096;每 3 个 Gated DeltaNet 接 1 个 full attention 42 blocks,hidden = 2,560;每 5 个 sliding attention 接 1 个 full attention
本课 C hook 第 24 个 block:零基编号 23,full attention block 之后 第 30 个 block:零基编号 29,full attention block 之后
容易混淆之处 layers.22 是 linear_attn,没有该层的 self_attn PLE 的 256 维是每层额外输入,不是 residual 宽度;后 18 层存在 KV sharing,模型不是简单重复标准 Transformer

示例图片为正方形:Qwen 若处理后为 512×512,则有 1,024 个视觉 patch,经 merger 得到 256 个视觉 token。Gemma 按当前 processor 的 max_soft_tokens=280 处理正方形时,resize 到 768×768:2,304 个真实 patch,pad 到 2,520;pooling 得到 280 个槽,去掉 24 个 padding 槽后,实际有 256 个视觉 token。280 是这里的预算,不保证每张图都有 280 个有效 token。 长宽比变化时数量也会变化,代码必须读实际 mask,不能硬编码图中的 256。Gemma processor 源码

02 · 模型与 SAE,各自吃什么、输出什么

对象 输入 输出 训练时更新谁?
MLLM 图片像素、官方 chat template 编码的 input_ids、attention mask,以及 processor 生成的视觉位置/网格元数据 完整模型可输出下一 token 的 logits:Qwen [B,L,248320];Gemma [B,L,262144]。采集激活时可只运行 model.model(...),省掉 LM head 全部冻结,eval()、no_grad()、use_cache=False
hook C 位置当前一次 forward 的 block 输出 [B,L,d] 按位置标签与有效 mask 选取、打散后的 [N,d] hook 只读取并 detach,不替换模型计算
SAE encoder 固定归一化后的一个 hidden vector x ∈ R^d 非负稀疏 z ∈ R^65536,每 token 最多 k 个非零值 更新 SAE encoder
SAE decoder 同一 token 的稀疏系数 z 重构 x_hat ∈ R^d;反归一化得到 h_hat 更新 SAE decoder;目标是原 hidden,不是图片像素或答案文本
数据选择 每条样本的所有有效 token 的 z,以及 I/Q/Ans 来源标签 三份样本指纹、激活 feature 集合、相似候选与新增覆盖 不自动把“激活多”解释成质量高

d 是一个 token 向量的坐标数,不是概念数;第 17 个 hidden 维度不天然代表“红色”。SAE 希望把原来叠加在这些坐标里的信息,分解为更容易检验的字典方向。但单个 feature 仍可能多义、碎片化,或者只反映位置与格式。

图片位置也在语言主干里,但不因此变成文本

对一条 图片 → 用户问题 → 已有答案 的样本,给每个位置保留来源标签:

池 选择哪些位置 该位置能看到什么 用于数据选择的意义
I:image slots processor 展开后真正被视觉向量替换的 image token;排除图片边界标记 图片视觉编码与此前序列上下文;不能看到后面的问题 图像内容与视觉语义;同图不同问,I 不应被当成问题理解指纹
Q:user text 图片之后的真实问题文本 token 图片及截至当前位置的问题前缀 问题意图、视觉属性查询、关系/计数/OCR 等任务;前面的 Q token 看不到后面的词
Ans:assistant text 数据集里已有答案的真实文本 token,teacher forcing 输入 图片、问题、此前答案以及当前位置已输入的答案 token 回答内容、知识和表达方式;不是答案正确性的证明

以上因果解释适用于本课的图在前、问题在后排序及这两个 checkpoint 的配置。Gemma E4B 的 use_bidirectional_attention 为 null,不要把其他 Gemma 变体的图像双向 mask 套过来。视觉编码器内部可全局读取图片,不代表 LLM 图片位置可以读取未来的问题。

本课的单图样本统一把首轮 user 内容规范为 [image, question_text],再使用官方 chat template;保留正文和真实轮次,并记录这一排序规则。部分来源把问题文本放在图片之前,直接沿用会让前置 Q token 看不到图片,不能套用上表。多图或顺序具有特殊含义的样本留待独立方案处理。

不把所有位置不加区分地喂给 SAE。 丢弃 padding、system、角色/轮次/图片边界等模板 token;保留真实 I/Q/Ans。图片较多并不应自动获得更高权重。先按来源与图片抽样,再在各池中限额均匀抽 token。真实多轮保留对话历史;同一图片附带的独立 VQA 问答应拆成独立样本,不能拼成虚假的对话。

Ans 是否参与取决于目标:本课筛选的是完整 SFT 样本,所以参与;若只研究“输入图片 + 问题”的表示,就去掉 Ans,并用相同条件重训/重评。用于验证最终任务的参考答案不能混入 SAE 训练集。teacher forcing 只是读已有训练答案,不会自动让错误答案变正确。

03 · 用什么数据:先覆盖目标分布

SAE 训练集是产生 hidden 的输入语料;SAE 的重构目标则由冻结模型提供,不需要人工 feature 标签。以 LLaVA 风格的单图指令数据为目标,采用“广泛图文概念 + 属性/关系问答 + 少量 OCR + 指令格式”的组合。这里先做英文图文;面向中文或医学、图表等新领域时,要替换相应份额并重新验证,不能宣称这份配比普遍最优。

每个模型、每个主 SAE 的正式上限为 200M 次有效激活暴露,先用包含在其中的 20M 做 pilot。一次暴露是一条 [d] 向量进入一次 SAE 更新;它不是原始文本 token 数,也不是完整 MLLM forward 的序列 token 数。重复抽样计入暴露预算;同时记录独立图片数、独立文本 token 数与 forward 总量。Qwen 与 Gemma 各训一个主 SAE,总上限 400M,A/B 可选实验另计。

来源 使用的 train 数据 激活预算占比 每模型上限 为什么放进来
广泛图片描述 pixparse/cc3m-wds · 镜像 20% 40M 物体、场景、长尾概念;WebDataset 内含图片和 caption
自然图像描述 jxie/coco_captions · 镜像 15% 30M 接近 COCO/LLaVA 的图像域;同图多 caption 按 image ID 分组
细粒度描述 the_cauldron,localized_narratives · 镜像 10% 20M 更细的实体、动作与关系;文本长时限制每样本取样数
常见视觉问答 同上,vqav2 20% 40M 从“描述什么”扩展到“在问什么”
组合关系问答 vikhyatk/gqa,train_balanced · 镜像 15% 30M 属性、空间关系和组合问题;展开每图的独立 QA
知识相关问答 the_cauldron/aokvqa 5% 10M 图像线索与常识结合
图片中的文字 the_cauldron/textvqa 5% 10M OCR 与基于图片文字的问答
目标格式桥接 HuggingFaceH4/llava-instruct-mix-vsft · 镜像 10% 20M 真实 messages/images 格式;按子任务分层,避免固定模板支配
合计 每个来源交错抽样 100% 200M 这是一份工程混合方案,不是某篇论文的原配方

表中镜像是仓库访问入口,不保证当前位置的下载速度或所有文件直连;部分请求会重定向到 Hugging Face。固定数据 revision、split、过滤规则与许可证记录。H4 的混合数据不是原始 LLaVA-Instruct-150K。原始 LLaVA-Instruct-150K 的标注还需要配套 COCO 图片,不能只下载对话 JSON 就开始抽视觉激活。

来源配比与 token 池配比是两层抽样。 在每个来源中,先以 I 50% / 文本 50% 为起点;问答来源的文本份额在 Q 与 Ans 中等分,caption 来源的文本份额给真实 caption/Ans,排除人为添加的固定“Describe this image”请求。短文本不能靠反复重复几个 token 填满预算,应扩大图片/样本覆盖并报告实际比例。无需额外加纯文本,图文样本已有大量文本位置;纯文本是后续泛化对照,不能给 A/B 产生视觉激活。

入库前完成:坏图/空文本检查 → 统一 RGB 与官方 template → 图片 ID、精确 hash 和近重复分组 → 排除最终评测图片及其近重复 → 按图片组切分 90/5/5 train/validation/test,seed=42。COCO、VQAv2、LLaVA 等来源可能复用图片,不能按行随机切分;某些第三方 train split 也包含 COCO val 图片。额外报告与候选筛选池的重叠;以未见图片/来源的评估检验泛化。

04 · 从原始数据到训练更新

每个 token 独立成为一个 SAE 训练样本,混合后打散。源图片和对话不会丢失:它们的 ID、token 位置与来源标签随缓存保存,后续可以回看某个 feature 激活最强的原图区域与文本。

FIGURE 02 · THE TRAINING LOOP训练的边界在哪里?点选步骤,或播放一次完整管线
01/ 07
数据入库先保证“这张图”与“这段对话”对应图片 + messages + source + image_group_id

坏图/错配过滤,图片 hash/近重复分组,排除评测重叠;按图片组切分 90/5/5。独立问答分别展开,真实多轮保留历史。

MLLM 冻结 · Qwen3.5-9BSAE 可训练 · 4096 → 65,536 → 4096
每模型主 SAE:20M pilot ⊂ 最多 200M 暴露每次更新 4,096 个有效向量
20%
15%
10%
20%
15%
5%
5%
10%
CC3M 20%COCO captions 15%Localized narratives 10%VQAv2 20%GQA 15%A-OKVQA 5%TextVQA 5%LLaVA mix 10%

比例按实际送入 SAE 的有效向量计;不是数据行数,也不是 MLLM 前向处理的全部 token。200M 是工程上限,没有实测训练曲线。

冻结 MLLM → forward → hook → 采样 → 固定归一化 → SAE → 重构 loss → 仅更新 SAE。 SAE 并不串接在正常生成路径中,不要求 MLLM 学会使用它;冻结模型每次提供原始 hidden target。不要在 no_grad() 内运行需要更新的 SAE,只有 MLLM 的激活采集放在其中。

训练配方:先跑得对,再扩大预算

参数 本课主 SAE 的起点 必须记录或验证的事项
hook Qwen C=layers.23;Gemma C=layers.29 完整输出、零基层号;层位对照分别训练,不能混成一个字典
输入宽度 / 字典宽度 Qwen 4096 → 65536;Gemma 2560 → 65536 两套 encoder/decoder、统计和 feature ID;65K 是 65,536,不是词表
稀疏化 TopK(ReLU(u), k=64),对照 k=32/128 每 token 最多 k 个非零,不是整个 batch 共用 k;零值不算激活
重构 线性 decoder,decoder 每列单位 L2 范数;每步投影更新后重新归一化 避免字典尺度任意漂移;encoder 初始化为 decoder 转置,此后不绑权
归一化 用至少 100k 个代表性 train 向量估计向量均值 μ 与一个标量 s;固定 x=(h−μ)/s I/Q/Ans 使用同一组统计;按真实抽样比例估计。不同模型/hook 各估各的;不逐 token 单位化
优化器 Adam,lr=1e−4,β=(0.9,0.999),eps=1e−8,weight decay=0,grad clip=1 200 步 warmup 后常数 lr,按 validation 早停;不要把它写成已验证最优
全局 batch 4096 个激活向量;例如 microbatch 512 × 8 梯度累积 不是 4096 张图;多卡时计入全部 rank 的有效向量
精度 冻结主模型与缓存 BF16;SAE 权重、归一化和 loss 用 FP32 起步 不先量化主模型;量化会改变 SAE 的训练对象
激活缓存 约 65,536 向量的 shuffle buffer;按 source/pool 打散 只缓存需要的位置;记录样本 ID、模型/processor revision、hook、mask 与统计 hash
预算 20M pilot,正式最多 200M 暴露/模型/主 hook batch 4096 对应约 48,828 次更新;早停时报告实际暴露与重复率
dead features feature 在最近 10M 次全局暴露内无 z>1e−6 记为 dead 未积累完整窗口前不按该规则宣布死亡;按池分别记录使用率
AuxK dead-feature 辅助重构,系数 1/32;k_aux=min(2048, dead_count) 两个主 SAE 使用同一明确配置;不是所有库的默认值,采用下述定义

定义 D ∈ R^(d×K) 为 decoder 字典,encoder 为 W ∈ R^(K×d)。每个 D[:,j] 是第 j 个 feature 的重构方向;z_j 是当前 token 使用它的强度。

x=(h−μ)/s,s2=Etrain∥h−μ∥22/d x=(h-\mu)/s,\quad s^2=\mathbb{E}_{train}\|h-\mu\|_2^2/d
u=W(x−bdec)+benc,z=TopK⁡64(ReLU⁡(u)),x^=Dz+bdec u=W(x-b_{dec})+b_{enc},\quad z=\operatorname{TopK}_{64}(\operatorname{ReLU}(u)),\quad \hat{x}=Dz+b_{dec}
Lrec=mean⁡b∥xb−x^b∥22d \mathcal L_{rec}=\operatorname{mean}_b\frac{\|x_b-\hat{x}_b\|_2^2}{d}

为使 AuxK 的实现没有歧义:e=stop_gradient(x−x_hat);只在 dead 集合内从 ReLU(u) 选取最多 k_aux 个系数,记为 z_dead;辅助重构为 D z_dead,不加 decoder bias。

Laux=mean⁡b∥eb−Dzdead,b∥22∥eb∥22+10−8,L=Lrec+132Laux \mathcal L_{aux}=\operatorname{mean}_b\frac{\|e_b-Dz_{dead,b}\|_2^2}{\|e_b\|_2^2+10^{-8}},\qquad \mathcal L=\mathcal L_{rec}+\tfrac1{32}\mathcal L_{aux}

无 dead feature 时令辅助项为 0;初始 bias 为 0。TopK 已控制稀疏度,本配方不再叠加一个未经调参的 L1 惩罚。这个归一化辅助 loss 是本课选定的实现约定;不要把它与其他 SAE 仓库的不同 reduction、残差归一化或 batch TopK 默认值混用。TopK、dead-feature 处理及重构/行为多维评估的依据可参见 Scaling and evaluating sparse autoencoders。

65K 不意味着训练代价小:两块稠密权重约为 2×d×K 参数。Qwen SAE 约 5.37 亿参数,Gemma SAE 约 3.36 亿;FP32 参数、梯度及 Adam 两份矩状态合计约 8.6 GB / 5.4 GB(十进制),尚未计主模型、activation、临时张量与框架开销。先测显存;不足时减 microbatch、累积梯度,或将 32K 作为明确记录的独立配置。65K 在两个模型上的扩张倍数分别是 16× 和 25.6×,不能据此视为容量完全匹配的科学对照。

可运行的 hook 烟雾检查

下面代码只验证“模型确实经过该模块、形状正确、image mask 与序列对齐”,不是完整训练器。需要可加载模型的 GPU 环境、支持这两个模型的 Transformers 版本,以及 Gemma 已获准的模型访问。先对安装版本运行,再锁定版本与模型 revision;本文没有执行权重加载。

pythonimport torch
from PIL import Image
from transformers import AutoProcessor, Qwen3_5ForConditionalGeneration, Gemma4ForConditionalGeneration

which = "qwen"  # 改成 "gemma"
specs = {
    "qwen": ("Qwen/Qwen3.5-9B", Qwen3_5ForConditionalGeneration, 23, 4096),
    "gemma": ("google/gemma-4-E4B-it", Gemma4ForConditionalGeneration, 29, 2560),
}
model_id, cls, layer, d = specs[which]
processor = AutoProcessor.from_pretrained(model_id)
model = cls.from_pretrained(model_id, dtype=torch.bfloat16, device_map="auto")
model.eval().requires_grad_(False)
path = f"model.language_model.layers.{layer}"
modules = dict(model.named_modules())
assert path in modules, path
print(path, type(modules[path]).__name__)

image = Image.open("example.jpg").convert("RGB")
messages = [
    {"role": "user", "content": [
        {"type": "image", "image": image},
        {"type": "text", "text": "What is in this image?"}]},
    {"role": "assistant", "content": [
        {"type": "text", "text": "Replace this with the dataset's actual answer."}]},
]
batch = processor.apply_chat_template(
    messages, tokenize=True, add_generation_prompt=False,
    return_dict=True, return_tensors="pt",
).to(model.device)
cache = {}
def capture(_module, _args, output):
    h = output[0] if isinstance(output, tuple) else output
    assert h.ndim == 3 and h.shape[-1] == d
    cache["h"] = h.detach()

handle = modules[path].register_forward_hook(capture)
try:
    cache.clear()  # 每次 forward 都清空,避免误用上一样本的激活
    with torch.no_grad():
        _ = model.model(**batch, use_cache=False)
    h = cache.pop("h")
    ids = batch["input_ids"].to(h.device)
    valid = batch["attention_mask"].to(h.device).bool()
    image_mask = ids.eq(model.config.image_token_id) & valid
    assert h.shape[:2] == ids.shape
    assert image_mask.any(), "图文样本应存在真实 image slots"
    print("all:", tuple(h.shape), "image:", tuple(h[image_mask].shape))
    # Q / Ans 用模板渲染时记录的角色正文跨度对齐,不能用“非 image”代替。
    # 抽样后再离开 no_grad,用 FP32 SAE 计算 loss/backward/optimizer.step。
finally:
    handle.remove()

生产数据处理需要补齐 Q/Ans mask:记录 chat template 中每个消息正文的 token span,与 processor 展开 image slots 后的序列对齐;支持 assistant mask 的模板可利用该能力,但要检查 mask 是否全零、是否覆盖真实答案。用单图、纯文本、独立 QA、真实多轮和 padding 样本逐个检查。不要通过 decoded 文本里搜索答案字符串定位,重复词与特殊 token 会造成错位。对齐完成后,assert 三个池互斥、均不含 padding,且所有入池位置都有来源记录。

第一轮限定单图、文本上限约 512 token、总序列上限 2048;超过上限的样本显式跳过并记录比例,不截断半个图像 span。Qwen 固定 processor 的像素预算(如 65,536–1,048,576);Gemma 固定 max_soft_tokens=280 起步;两者保留长宽比,缓存与正式筛选使用相同配置。OCR 受分辨率影响,后续提高预算必须重验表示分布。

05 · 一个 65K 字典,里面到底装什么

字典不是预先命名的概念表,也不是按比例分给图片/文本的内存。同一个 C hook 上的 I、Q、Ans 向量,共享同一套 encoder、decoder 和 65,536 个 feature ID。 抽样时 50% 图像位置并不意味着训练后恰好 50% feature 属于图片。

FIGURE 03 · ONE SHARED DICTIONARY65,536 个位置,没有预划的模态分区同一模型、同一 hook;每个 token 只使用少量方向
65,536 槽;示意激活 64 个256 × 256 个槽 · 无模态分区
编号和命名仅用于本图,不对应两个模型的真实 feature。
同一个字典中的 featureF00042 · 苹果 / 物体候选
图文共同激活候选
图片 I
0.92
问题 Q
0.48
答案 Ans
0.65

相同 ID 在图片和文字中活跃,是跨模态候选;仍需相关图文、负例与干预验证。

共享 encoder:65,536 × 4096共享 decoder:4096 × 65,536本 token:64 / 65,536 活跃(0.098%)

这里恰好点亮 k 个槽以演示稀疏预算;真实 ReLU + TopK 可以少于 k。条形数值为合成数据。I/Q/Ans 标签用于训练后统计,不是分配给三套字典。模型切换仅演示尺寸;两套真实字典的 feature ID 不对齐。

点击 feature 查看它在三类位置上的示意激活。改变 k 只改变每个 token 的稀疏预算,不改变字典槽位数。图中把 65,536 个槽缩略为一个 256×256 网格;点亮的是合成示例,数值不构成实际模型的 feature 发现。

训练后可能观察到的 feature 如何发现与命名 不能据此直接断言什么
视觉偏好:颜色、形状、物体、局部区域 I 池激活多,回看不同原图的高激活 patch/visual token,并做区域遮挡 激活区域不是严格因果定位;深层视觉 token 已可能读取整图
文本偏好:词法、句式、回答格式 Q/Ans 池激活多,查看不同来源的高激活文本跨度 不等于“无用”;任务形式本身可以贡献数据多样性
任务/融合相关:计数问题、文字读取、属性判断 Q/Ans 在有图条件下有稳定激活,换图/换问后变化合理 “位于文本 token”不等于“只含文本信息”
跨模态候选:图片中的苹果与文字 apple 同一 feature 在相关图片和文本上都激活,并通过对照排除模板/位置 共用字典不保证同义图文自动对齐到同一 feature;一个 feature 也可能多义
格式、位置、噪声或 dead feature 激活与模板、长度、数据源或数值异常强相关,或长期不激活 不能把所有 65K 槽当成已解释的 65K 语义概念

训练时不分配语义类别;训练后才统计。 对每个 feature 记录 I/Q/Ans 的激活概率、强度、source 分布与 top examples,按池样本数归一化;允许多个标签、未解释与噪声类别。需要跨模态语义一致性时,增加图文对应、图像替换、问题改写和 feature 干预实验。VL-SAE 使用专门的显式对齐与模态 decoder 来推动一致概念;普通混合 TopK SAE 不自动获得同样性质。VL-SAE

一轮建议抽查 100 个活跃 feature,每个回看至少 20 个不同图片组/样本的 top examples,并包含随机激活与负例。对主 hook,固定同图与前缀、只改后置问题时,I 应在数值容差内保持不变,而 Q/Ans 可以改变;固定问题换图、遮挡相关区域,则检验文本位置的 feature 是否确实依赖视觉。

06 · 怎样拿这些特征筛数据

先对所有有效 token 逐个编码成 z,再聚合。先平均 hidden 再经过 SAE 会改变非线性稀疏编码的结果。对每条样本分别保存 v_I, v_Q, v_Ans:各池 mean(z) 后 L2 归一化用于相似度;另外保存超过 feature 阈值的激活集合,用于覆盖。

目标 可实施的步骤 关键边界
精确去重 图片 hash + 规范化问题/答案 hash,先去完全重复 不要仅凭图片相同删除问答
语义重复候选 在各池稀疏指纹上找相似邻居,再联合 I/Q/Ans 判定 同图不同问、同问不同答案必须进入标注校准集;不设一个凭空选的通用阈值
语义冲突 I、Q 相似而 Ans 不同,标记为“待核验” 可能是互补答案,也可能是错误;SAE 相似度不裁决事实
多样性选择 每次优先加入可靠 feature 的新增覆盖;结合图像组、来源/任务配额和样本或 SFT-token 成本 高频模板、罕见噪声不应获得额外奖励;长样本不能仅凭更多 token 占便宜
最终检验 在固定样本量或 SFT-token 预算下,与随机、hash 去重及 dense embedding 选择对比 原始 feature 覆盖数不能直接跨不同 SAE/不同字典比较;必须看下游收益和误删

TopK 的每 token 非零数接近固定,因此“激活总次数多”不是多样性分数。 相似度阈值与覆盖阈值在 held-out 校准集上选择,并检查稀有任务与回答长度的偏差。给每个 feature 保存数据源证据;新覆盖只在活跃、稳定且排除明显模板/噪声的集合中计分。

07 · 什么结果才算可以使用

不要只看总 MSE。总体 loss 很好可能只是图片位置占多数,把问题与答案的重构问题掩盖了。

验收层面 本课建议的启动门槛 / 比较方式 不通过时先检查
数据与张量 hook 命中;d、token 数、I/Q/Ans mask 均通过断言;跨 split 无图片组泄漏 模型版本、模板跨度、padding、旧 cache、图像与对话错配
稀疏与活性 L0≤64;完整 10M 暴露窗口后 dead 比例先以≤10%作为排查门槛 输入统计、学习率、初始化、AuxK、单一来源过采样
重构 validation 总 FVU 先以≤0.15、各池≤0.25为排查门槛;按池用自己的验证均值计算分母 不同池尺度/难度、k 太小、字典不足;门槛不是论文公认标准
功能保持 真实用 h_hat 替换 hook 输出,teacher-forced answer CE 增幅先以≤0.1 nat/token、任务准确率下降≤1pp为排查线 必须重跑后续模型;不能加回原重构残差,那会把误差隐藏掉
特征含义 top examples + 随机/负例 + 换图/换问/遮挡对照;记录不能解释的 feature 位置、格式、长度和来源偏差;不能凭一张热力图命名
去重误删 至少 500 对人工校准样本,覆盖同图不同问、同问不同答与近重复图 按任务与来源报告 precision/recall;阈值只在校准集上调
选择是否有用 固定预算做随机、dense、SAE 对照;至少 3 个随机种子,报告均值与波动 是否仅靠特定来源/长度配额获益;是否因测试集重叠造成虚高

FVU 用 Σ||h−h_hat||² / Σ||h−mean(h)||²;按 I/Q/Ans 分别算,低方差池单独报告绝对误差,避免不稳定比值。所有数值门槛都是诊断起点,最终能否用于选择数据,要由误删率、任务保留与下游 SFT 决定。

训练结束至少保存:SAE 权重与 bias、μ/s、K/k、模型与 processor revision、Transformers 版本、完整 hook 路径、数据 split/hash/采样配置、实际预算、按池验证指标、feature 使用统计与 top-example 索引。没有这些信息,一个权重文件很难被正确复用。

08 · 哪些来自研究,哪些是本课的选择

依据 能支持的结论 本课没有从中推出的结论
SAE-V,ICML 2025,PKU 团队 多模态内部 feature 可以帮助分析对齐,并用于数据筛选 不证明 Qwen3.5-9B layer 23、Gemma E4B layer 29 或本课混合比例最优
VL-SAE,NeurIPS 2025,ICT/UCAS 跨模态统一概念需要专门考虑表征/激活对齐 不把普通混合 SAE 的同一 feature ID 自动视为已对齐语义
OpenAI:Scaling and evaluating sparse autoencoders TopK 控制稀疏度,dead latents 与功能评估都重要 不把文本 SAE 的所有默认值当成多模态已验证配方
Qwen-Scope,Qwen 团队 SAE 特征可用于冗余、覆盖与数据相关分析 不把它当成已公开验证本课图文混合数据与两个指定 hook 的证据
本课方案 两模型分开训练;C 为主、A/B 为对照;I/Q/Ans 共用每模型的 65K 字典;200M 上限 仍需运行、校准与消融;图中的 feature 值不是测量结果

读完本课后,应能把四件事分开:输入图片/文本是什么,冻结模型产生的 hidden 是什么,SAE 学到的字典方向是什么,数据选择使用的样本指纹是什么。 下一步是先用 20M pilot 检查这些边界,再决定是否扩大预算。

✳

理解在生长,笔记也会继续。

编辑这篇手记 ↗下载 Markdown ↓

IN THE MARGINS / 页边讨论

一起把问题想清楚

正在读取讨论…

在 GitHub 留下评论 ↗

使用 GitHub 账号参与讨论。评论公开,并同步显示在这里。

搜索整本手记 · 中文 / English