本课要训练的是一个读取冻结模型内部表示的 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;进入语言主干的是视觉编码后的向量,占据序列中的图片位置。
model.language_model.layers.23[N, 4096]选择有效位置 → 固定 μ/smodel.language_model.layers.23带图片上下文的颜色查询;可含任务意图与视觉关联。
尺寸来自配置;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 激活最强的原图区域与文本。
图片 + messages + source + image_group_id坏图/错配过滤,图片 hash/近重复分组,排除评测重叠;按图片组切分 90/5/5。独立问答分别展开,真实多轮保留历史。
比例按实际送入 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 使用它的强度。
为使 AuxK 的实现没有歧义:e=stop_gradient(x−x_hat);只在 dead 集合内从 ReLU(u) 选取最多 k_aux 个系数,记为 z_dead;辅助重构为 D z_dead,不加 decoder bias。
无 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 属于图片。
相同 ID 在图片和文字中活跃,是跨模态候选;仍需相关图文、负例与干预验证。
这里恰好点亮 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 检查这些边界,再决定是否扩大预算。
IN THE MARGINS / 页边讨论
一起把问题想清楚
正在读取讨论…
使用 GitHub 账号参与讨论。评论公开,并同步显示在这里。