VLM 明明会数数,为什么还是答错?
一张图里有 7 个红色小圆点,模型看完以后回答:5。
这件事听起来像一个很普通的多模态失败案例。我们自然会以为:模型没有看清、没有把对象分开、或者干脆凭语言先验猜了一个常见数字。可是这篇论文最反直觉的地方在于,它问了一个更尖锐的问题:如果模型内部其实已经有“7”这个信息,只是最后说出口时偏成了“5”呢?
这不是语义上的安慰。研究者训练了一组很简单的 probe 去读 VLM 中间层激活:一个读真实数量,一个读模型最终会输出的数量,还有一个只判断模型这次会不会错。结果显示,在四个 VLM、五个计数数据集上,很多时候正确计数是可从隐藏状态里读出来的;问题不总是“数不存在”,而是“数在里面,但读出方向和最终答案没有对齐”。

先把三个概念放在桌面上
第一个概念是 VLM 计数。数东西看似简单,其实同时要求模型完成四件事:找到相关对象,把它们和干扰物分开,给每个对象建立稳定对应关系,最后把视觉证据映射成一个精确数字。任何一步松动,答案都会错。
第二个概念是 probe。它像一根很细的探针,不改变模型,只是在某一层隐藏状态上训练一个小分类器或回归器,问:“这里面能不能读出某个信息?”如果 probe 能从第 20 层激活里读出真实数量 7,我们至少知道那一层包含了和 7 强相关的结构。
第三个概念是“可读出”不等于“会说出”。一个人脑子里可能知道钥匙在左口袋,但手习惯性摸右口袋。对模型也是一样:隐藏状态里可以同时存在“真实数量”的方向和“输出答案”的方向。论文用 SVCCA 比较这些方向是否重合;如果相似度低,就说明模型内部有信息,但最终生成时沿着另一条路走了。
只看最终答案,会把问题看扁
过去很多 VLM 计数论文做的是行为评测:给模型图片,问有几个对象,统计准确率。这当然重要,因为它告诉我们模型不可靠。但它解释不了失败发生在哪里。
直觉上有三种可能。第一,视觉编码阶段就没看见正确对象,隐藏状态里根本没有正确数量。第二,模型看见了,也编码了,但语言输出阶段没有用上。第三,模型在某些复杂图像里会产生一种内部“我要错了”的信号,只是普通解码流程没有利用它。
这篇论文的设计就是把这三种可能拆开。研究者构造了四组合成计数数据,每组 1170 张 512×512 白底图像,数量从 1 到 9,按 80/20 分层划分训练和测试。四组数据改变颜色和形状复杂度:单色单形、单色多形、多色单形、多色多形。除此之外,他们还在 CountBench 上做外部验证,并测试 InternVL2-1B、InternVL2-4B、Qwen3-VL-2B-Instruct、Qwen3-VL-8B-Instruct 四个模型,全部 zero-shot、greedy decoding。
这套设置的好处是,问题被压得足够干净:不是开放世界里“猫算不算一只”“遮挡物算不算”的语义争议,而是 1 到 9 个非重叠对象的精确计数。这样如果模型仍然错,我们就更有理由追问内部表征和输出之间的关系。
三个探针,其实是在问三句不同的话
论文没有只训练一个“真实数量 probe”。它同时训练三类读出器。
第一类问:隐藏状态里能不能读出 ground-truth count,也就是真实数量。第二类问:隐藏状态里能不能读出 model output count,也就是模型最后会说出的数字。第三类问:隐藏状态里能不能判断这次输出会不会错。
这三个问题差别很大。真实数量 probe 像在问“模型看见的世界是什么样”;输出 probe 像在问“模型最后准备怎么回答”;错误 detector 则像在问“模型内部是否已经露出失败征兆”。如果只做第一个,我们只能说模型内部有信息;如果只做第二个,我们只是在复现模型行为。把三者放在一起,才有可能看到“知道”和“说出”之间的裂缝。

实验结果有两个关键细节。
第一,单标量 affine probe 不够强,尤其在较后层很难稳定解码数量;但 multiclass linear probe 仍然有效。除这个弱基线外,Logistic、Circular、MLP 等 probe 多数超过 80% F1,在 Qwen3-VL-8B 激活上甚至接近完美。这一点很重要:如果只有复杂 MLP 能读出数量,我们会怀疑 probe 自己学会了任务;但较简单的 Logistic 和 Circular 也能做到,说明隐藏状态里确实有相对规整的计数结构。
第二,真实数量 probe 往往在较早层就达到平台,而输出 probe 更靠近最终层才达到峰值。换句话说,模型可能很早就形成了“图里有几个”的信息,但“我要说哪个数字”是在后面的生成流程里逐渐定型的。InternVL2-1B 是一个更有趣的例外:它的输出 probe 大约卡在 60–65%,可同一批激活上的错误 detector 却能超过 90% F1。也就是说,预测模型具体会说什么很难,但预测它会不会错反而容易。
这就像你不一定知道一个学生会写下哪个错误答案,但你能从他的草稿状态看出“这题要错”。
SVCCA:不是有没有信息,而是信息走哪条路
到这里我们还不能马上下结论。probe 能读出真实数量,只说明信息存在;它不说明这个信息和最终输出用的是同一套内部方向。也许真实数量只是隐藏状态里的旁路残留,和解码完全无关。
论文用 SVCCA 来处理这个问题。可以把 SVCCA 理解成一种“方向相似度”测量:两个 probe 可能参数写法不同,但如果它们依赖的是同一个低维子空间,SVCCA 会给出较高相似度;如果一个沿东北方向读,另一个沿西北方向读,相似度就低。分数接近 1 代表对齐,接近 0 代表近似正交。
结果支持一个“子空间错位”假说。Figure 3 显示,MLP 和 Circular probe 的 ground-truth 方向与 output 方向处在低 SVCCA、接近正交的区域;Linear probe 对齐更高,但也有限,尤其 Logistic regression 仍显示明显错位。更关键的是,这种低对齐并不能简单归因于“两个 probe 最好层差得很远”。论文把 SVCCA 和最佳层差放在一起看,发现即使层差很小,低 SVCCA 仍然存在。

这一步把故事从“模型内部有没有数”推进到“数如何被组织”。我们平常说模型“知道但没说出来”,很容易变成拟人化描述;这里的贡献在于把这句话变成一个几何命题:真实计数和输出计数在同一激活空间中可被读出,但它们依赖的读出子空间不充分对齐。
因果 steering:把方向推一下,答案真的会变好吗?
probe 和 SVCCA 仍然有一个老问题:相关不等于因果。一个 probe 可能找到的是计数的影子,而不是生成答案真正用到的方向。为了排除这一点,论文做了 activation steering。
方法很直接。先让 InternVL2-1B 正常回答,得到 baseline 预测。然后在 Logistic ground-truth probe 表现最好的层上加一个 forward hook。假设真实答案是 y,模型初始答案是 ŷ,就取 probe 中“真实类别方向”和“错误输出类别方向”的差,归一化后加到当前隐藏状态上。扰动强度用 α 控制,并按激活 RMS 缩放。作为对照,研究者还用同维度随机方向做同样扰动。
如果 probe 方向只是巧合,那么沿它推一下不应该系统改善计数。实际结果相反:在四组合成数据上,probe-derived steering 都能在一个中等 α 区间内把准确率抬到 baseline 之上。最清楚的例子是 diff_col_diff_shape:准确率从约 27% 提到接近 46%,约 19 个百分点提升。single color single shape 和 different color single shape 上也有约 6–8 个百分点的稳定收益。随机方向则没有这种效果,α 变大后通常单调伤害性能。
这个实验说明,probe 找到的方向不只是“旁观者变量”。它至少在局部线性范围内能影响生成答案。与此同时,论文也诚实地展示了边界:α 太大时,probe-derived steering 也会破坏模型;例如 sing_col_diff_shape 中蓝线大约在 α=45 后进入 destructive zone。这说明计数方向不是一个可以无限加强的魔法按钮,它更像一条局部可用的修正切线。
更实用的做法:不要改隐藏状态,只决定何时重问
既然直接 steering 有风险,一个更温和的方案是:不碰模型参数,也不修改隐藏状态,只用内部错误 detector 判断什么时候该让模型重新数一次。
具体流程是两步。第一遍,模型正常回答,同时从最佳 detector 层抽取激活,得到错误概率 s。如果 s ≥ τ,论文中 τ 固定为 0.5,就触发第二次提示;否则保留原答案。第二遍提示会带上原问题和模型的上一轮回答,并明确告诉模型“Your previous answer was ... That’s definitely wrong. The correct count should be:”。这里的 probe 不是替模型数数,而是一个选择性闸门:只在内部状态显示高风险时,才花第二次推理成本。

Table 1 的数字很能说明这个策略为什么有意义。Always Reprompt 对所有样本都重问,是最高预算基线,但它有两个问题:成本翻倍,而且会把原本正确的答案改错。Random-K 使用相同重问预算但随机挑样本,用来检查“选择性”本身有没有价值。论文的方法几乎总是超过 Random-K,说明 detector 不是随便挑了一批样本。
具体看几个数字:在 DC-DS 上,InternVL2-4B 从 34.62% 提到 50.21%,提升 +15.60 个百分点;在 SC-SS 上,InternVL2-1B 从 23.65% 到 35.11%,提升 +11.47;在 CountBench 上,Qwen3-VL-8B 从 79.92% 到 88.59%,提升 +8.66。整体上,论文报告最高 +15.6 个百分点,平均 +5.3 个百分点。Figure 5 还显示,错误检测 F1 和纠正收益强相关,ρ=0.803;当 detector F1 超过 90% 时,收益最大。
这也解释了为什么 Qwen3-VL-2B 的提升较小。它不是因为“重问”机制对 Qwen 没用,而是因为内部错误信号本身没那么好读。论文在 Table 3 的讨论里也指出,探针类型之间的差异小于 VLM 家族之间的差异:瓶颈更像是激活中错误信号的质量,而不是 detector 架构选择。
附录还有一个对照很有启发:用输出熵来决定是否重问并不可靠。在 Table 6 里,entropy-guided 在四个数据集中有两个出现负收益,比如 diff_col_diff_shape 是 -1.71%,sing_col_sing_shape 是 -3.42%;probe-guided 则对应为 +7.26% 和 +4.70%,在 sing_col_diff_shape 上达到 +16.24%。这说明“模型不确定”并不等于“模型会数错”。错误有时不是低置信度,而是内部表征和输出路径的错位。
这篇论文证明了什么,也没有证明什么
它证明的第一件事,是在受控 1–9 计数任务里,若干现代 VLM 的隐藏状态确实包含可读出的计数信息。这个结论不是来自一个大黑盒分类器,而是来自多种 probe、跨模型、跨数据集的层级扫描。
第二,它证明了“真实计数”和“模型输出计数”并不总是同一条内部道路。SVCCA 显示,尤其是非线性 probe 的子空间对齐很低,而且这种错位不能简单归因于最佳层不同。
第三,它给了因果证据:沿 probe-derived count direction 做适度 steering,可以把 InternVL2-1B 在合成计数集上的准确率抬高;随机方向没有同样效果。这让“probe 读到的方向和生成有关”比纯相关分析更可信。
第四,它展示了一个无需更新参数的实用改法:用内部错误 detector 选择性触发 self-correction,最高提升 15.6 个百分点,平均提升 5.3 个百分点,并且通常优于同预算随机重问。
但它没有证明这些结论已经覆盖所有 VLM。论文自己也列出限制:模型最大只到 8B,只覆盖 InternVL2 和 Qwen3-VL 两个家族;因果 steering 只在一个模型上做;合成数据到真实世界的迁移仍需验证;计数范围也限制在 1–9,没有进入 10 个以上对象、更强遮挡、更复杂语义类别的场景。
还有一个值得谨慎的点在附录 C:视觉 encoder 激活上的高错误检测 F1 可能部分来自场景复杂度相关性。对象越多、图越密,模型越容易错;探针可能学到“复杂图像更容易错”,而不是真正读出了模型是否推理失败。作者对此没有回避,这反而让主结论更清楚:我们需要区分真正的内部错误信号和数据分布中的捷径。
为什么这个结果重要
这篇论文的价值不只是“计数准确率又涨了几点”。更大的意义在于,它把 VLM 失败从一个行为现象拆成了三个层次:视觉信息是否存在,内部读出方向是否对齐,错误信号能否被利用。
如果失败是第一层——模型根本没看见对象——那我们需要更好的视觉编码、更强 grounding、更合适的数据。如果失败是第二层——数在里面但输出方向错了——那问题更接近 representation-to-decision alignment,可以通过 steering、probe-guided decoding、训练时对齐约束来处理。如果失败是第三层——模型内部知道自己要错但系统没用这个信号——那最便宜的工程改法可能不是重训模型,而是在推理时加一个内部状态监控器。
这也给“模型可解释性”一个很好的现实落点。probe、SVCCA、activation steering 常常被当成纯分析工具;在这里,它们串成了一条闭环:先发现内部计数信息,再定位表征和输出错位,再用因果干预验证方向,最后把错误 detector 变成选择性重问策略。
我们可以把它理解成一句朴素的话:不要只盯着模型说了什么,也要看它说出口之前,内部已经露出了什么。
对 VLM 来说,计数也许仍然不是一个解决的问题。但这篇论文至少告诉我们,有些失败不是“模型完全不会数”,而是更微妙、更工程化、也更可修复的失败:答案已经在表征里,只是没有沿正确路径走到嘴边。