看到这个题目的时候我第一反应是终于有人把VLM的视觉感知问题往“可验证”这个方向上认真推了一步。做过视觉语言模型微调的同学应该都有同感——模型嘴上很能说但眼睛经常不靠谱图上明明只有三只羊它能给你描述出五只物体明明在左边它咬定在右边问它颜色它能一本正经说出不存在的红色。这类问题靠常规的指令微调很难根治因为它本质不是“不会说话”而是“没看准”。ViCrit这个工作给出的解法思路是用一种带可验证奖励信号的强化学习代理任务专门去调VLM的视觉感知能力而不是继续堆数据、堆对话样本。这篇内容我会从问题定位、核心设计、任务实现、训练实操、踩坑记录五个层面拆开讲。无论你是做多模态模型训练、RL调优还是刚接触视觉语言模型评估都能在里面找到可以直接落地的经验。1. 先把问题摆清楚VLM的“眼睛”为什么不可信1.1 看得见不等于看懂了VLM的视觉感知问题业内已经吵了很多轮。最典型的是幻觉Hallucination模型在回答问题时会生成图像中根本不存在的物体、属性或关系。另一些则是细微但致命的错误——数量数错、方向搞反、位置混淆、属性张冠李戴。这些错误在纯对话场景里不一定显眼但一旦落到具身操作、自动驾驶、自动标注这些真实应用里代价立刻放大。我拿我自己之前在某个跨平台系统上复现过的一个例子来说给模型一张桌子上有两杯咖啡的图问它“桌上有几杯咖啡”它能答出“两杯”但紧接着问“咖啡杯分别在什么位置”它就编出了“一杯在盘子旁边、一杯在笔记本旁边”而实际上其中一杯根本不在画面里。这个现象很普遍模型在整体语义上是对的但局部细节完全是脑补。这类问题的根源不能简单怪模型“笨”。VLM的训练通常由两阶段组成先是视觉编码器加语言模型的对齐预训练然后是视觉指令微调Vision Instruction Tuning。问题在于指令微调阶段用的数据大多是图文对话模型只需要生成“看起来合理”的文本并不需要证明自己真的看准了。换句话说训练目标里压根没有“视觉感知正确性”这个硬约束。1.2 现有评估与训练管道的三个缺口要想解决感知不可信的问题先要看现有评估和训练方式为什么失灵。我总结了三个明显的缺口第一人工评估太贵也太慢。细粒度感知错误需要逐图逐句核对规模稍微一大就撑不住。而且不同标注者对“是否正确”的判断标准也不一致同一张图同一句话两个人可能给两个相反的结论。第二用VLM评估VLM会放大偏差。不少人尝试让大模型当裁判去检查另一个模型的输出但裁判模型自己也有同样的视觉幻觉倾向很容易把错的判成对的或者反过来。这种评估方式在文本领域效果还行放到视觉感知上就是错上加错。第三选择题式的评估有猜测空间。很多基准测试做成“哪个选项正确”的形式模型有25%甚至更高的盲猜概率而且排除法也能刷分。这种评估看似能跑分实际把感知问题退化成了语言推理问题测不出真正的视觉理解。结论很直接我们需要一种不依赖人工、不依赖另一个模型的判断、能自动给出确定性结果的质量信号。这就是ViCrit里“可验证”三个字的价值所在。2. 核心理念可验证奖励与代理任务的组合拳2.1 “可验证”到底在验证什么先说概念。可验证奖励Verifiable Reward在强化学习里的意思是奖励信号的产生不靠主观打分而是靠确定性规则或程序自动判断结果对错。类比一下就懂了——代码领域里的单元测试。写一个函数输入测试用例跑完看输出是不是和预期一致对就是过错就是挂没有任何模糊地带。把这个思路搬到VLM的视觉感知训练里就是让模型在给定图像和问题的情况下输出答案然后由一套程序化规则去判断这个答案是否符合客观事实。这里的“客观事实”来自数据的真值标注比如物体检测框、分割掩码、场景图标注、属性标签等。只要模型答案和真值能对得上就判定正确给正奖励对不上就给负奖励或零奖励。这个机制的好处是显而易见的奖励信号稳定、可复现、可规模化。不会像奖励模型Reward Model那样出现reward hacking也不会像人工反馈那样噪声大成本高。但可验证奖励有个关键前提——你必须能客观地判定答案对错。这就遇到一个新问题VLM要处理的视觉感知内容非常开放怎么设计一个既能被规则检查、又能真实反映模型感知能力的“问题集”答案就是代理任务。2.2 为什么不能直接训练“视觉理解”有人可能会问那直接把真实任务拎出来训练不就行了比如直接让模型在自动驾驶数据集上做目标检测或者直接在具身操作里做物体定位。理论上可以但实际不可行。原因有三点真实任务的标注成本极高、任务形式高度多样难以统一成奖励函数、以及端到端信号太稀疏模型根本不知道该往哪个方向优化。你要让机器人通过几百次试错学会“看准杯子再抓”这个探索空间大到几乎不可能收敛。所以业界通用做法是把复杂能力拆成一堆可控的、可自动判分的代理任务Proxy Tasks。所谓代理任务就是不直接训练最终产品而是训练一组支撑最终能力的子技能。这个思路特别像体育训练短跑运动员不会每次训练都跑完整比赛而是拆成起跑反应、步频、摆臂、弯道技术逐个拉练。每个子项都能单独计时、单独判分最后组合成完整比赛能力。放在VLM视觉感知里代理任务就是那些构成视觉理解基石的具体能力物体是否存在、数量是多少、物体之间的位置关系、物体的颜色/形状/材质属性、以及简单的空间方位判断。这些任务都有一个共同特点——答案可以被标注、被规则校验不存在主观争议。2.3 ViCrit的整体设计逻辑ViCrit的巧妙之处是把生成式批评器Generative Critic和可验证规则结合起来形成双通道校验。具体来说模型先对给定的图像和问题生成回答批评器对这个回答进行细致点评指出“哪里对了、哪里错了、哪里证据不足”然后可验证模块对批评器的结论进行规则化核验确认批评器说的到底对不对。最终以核验后的结论作为奖励信号反馈给策略模型。为什么要绕这么一圈因为很多感知任务虽然有标准答案但模型回答的措辞千变万化。比如计数任务模型可能回答“两只猫”也可能回答“我看到有两只猫”还可能回答“图上共有两只猫在沙发上”。规则直接匹配答案文本很容易误判而批评器可以把自然语言回答转化成结构化的判断再由规则去检查这个结构化判断是否与真值一致。换句话说批评器负责“翻译”规则负责“判卷”。翻译可以灵活判卷必须严格。这套组合既保留了自然语言的自由度又保证了奖励信号的确定性。3. 代理任务设计详解数据、提示与验证器实现3.1 我用一个具体例子拆解四个感知维度我在复现ViCrit类似思路的时候把代理任务分成了四个维度覆盖了VLM视觉感知中最容易被检测出问题的方面。这里逐一说明。存在性检测是个很好的起点。给定图像和提示词“图中是否存在[物体类别]”模型需要输出“是”或“否”。这个任务看起来简单但模型经常把“与场景相关的物体”误判为“场景中存在的物体”。比如图片里有个厨房场景、台面上没有香蕉但模型看到锅碗瓢盆和一个果盘往往倾向于回答“存在香蕉”因为它觉得厨房里“应该”有水果。存在性检测的验证规则最简单——直接用真值物体列表比对即可。计数任务是幻觉重灾区。提示词是“图中共有几个[物体类别]”。模型容易把不同角度、重叠遮挡的物体数重或者把倒影、装饰画里的物体也算进去。验证规则上需要在物体检测真值的基础上明确判定标准只统计真实物体框内且满足置信度阈值的实例不统计镜像和印刷品。空间关系任务是很多人的痛点。提示词是“[物体A]相对于[物体B]的位置在哪里”。这里的难点在于“相对位置”的定义。规则验证不能只看两个框中心的坐标差还要考虑视线遮挡和物体体积差异。比如一个巨大的沙发和一个小杯子出现在同一画面如果只看中心点杯子可能在沙发的“内心”位置但这在语义上并不成立。所以需要引入“可见区域重心”和“重叠比例”的联合判断。属性识别任务同样关键。提示词是“图中[物体]的颜色/形状/材质是什么”。这个任务验证比较直接——和属性标注做文本匹配但要注意同义词问题比如“浅蓝色”和“淡蓝色”。我当时给验证器加了一组同义词表效果提升很明显。3.2 验证器到底怎么写一份可参考的规则实现这里给一份我当时写验证器的核心逻辑伪代码可以参考这个模式去扩展自己的任务集。核心思想是两步判定先用结构化提取器将自然语言回答转成候选断言再用规则函数判定断言与真值的一致性。class PerceptionVerifier: def __init__(self, ground_truth): self.gt ground_truth # 包含类别、框、属性、关系等标注 def verify_existence(self, category, claimed_exists): actual_exists category in self.gt[object_categories] return claimed_exists actual_exists def verify_count(self, category, claimed_count, iou_threshold0.5): # 先按置信度和NMS过滤再做类别匹配 real_boxes self._get_valid_boxes(self.gt, category, iou_threshold) real_count len(real_boxes) # 允许模型输出容差±1避免边界截断干扰 return abs(claimed_count - real_count) 1 def verify_spatial_relation(self, a, b, claimed_relation): box_a self.gt[boxes][a] box_b self.gt[boxes][b] # 计算A相对B的方向向量基于可见区域重心 center_a self._visible_center(box_a, box_b) center_b self._visible_center(box_b, box_a) rel_vec center_a - center_b true_relation self._classify_direction(rel_vec) return claimed_relation true_relation def verify_attribute(self, obj, attr_type, claimed_value): true_value self.gt[attributes][obj][attr_type] return self._synonym_match(claimed_value, true_value)这里有几处容易踩坑。计数任务的容差别设太大我见过有人直接把容差设为±2结果模型从“数数”退化成“猜个大概”奖励信号完全失真。空间关系里的visible_center计算要处理好完全遮挡的情况——如果物体A被物体B完全挡住这个样本应该直接跳过不参与训练否则模型学到的是噪声。3.3 批评器生成判断时的格式约束在这个流程里批评器扮演的是“答题卡转译员”。为了让规则验证能稳定工作必须约束批评器输出为结构化JSON。我在实验里试过自由文本让规则去解析结果各种失败——有人称切换、有语言混杂、有前后矛盾。推荐让批评器输出这样一段{ claim: 图中存在两个红色杯子, structured_claims: [ {type: existence, object: cup, value: true}, {type: count, object: cup, value: 2}, {type: attribute, object: cup, attr: color, value: red} ] }规则验证器只读取structured_claims字段做判定。一旦模型回答中没有任何可验证的断言直接给零奖励不尝试做模糊匹配。这个“零容忍”设计一开始可能会让模型输出很多不可解析的句子但跑几百步之后模型会自然学会说出能被校验的结构化内容。4. 从数据到训练一套可复现的实操流程4.1 数据管线怎么攒出一批高质量的训练样本拼任务设计只是第一步样本从哪里来才是决定上限的地方。我当时的数据来源主要有三个公开的目标检测与分割数据集通过脚本把场景图转成自然语言问题和答案合成渲染引擎生成的模拟场景可以精确控制物体出现的位置、数量和属性以及人工种子样本加模型辅助扩展的混合方案。公开数据集转问答是最实惠的起点。以某个公开的目标检测数据集为例每张图都有物体框和类别标签把这些信息转成模板提问即可。合成场景数据则用来补充长尾分布——比如“一只在桌子底下的猫”、“三个遮挡一半的杯子”这类罕见但关键的场景真实数据集中很难凑够数量。数据平衡上我发现一个非常实际的问题VLM在数物体数量时少量物体1-3个的准确率极高4个以上就开始崩。如果训练集里小数量样本占90%模型很快学会“说个2到3之间的小数字”在这个子集上刷到高准确率真正的能力并没有提升。所以构造数据时要刻意增加困难样本占比我最终把数量在6-10个的样本比例调到30%以上模型的数数能力才出现可观察的改善。另外回答的多样性不能忽略。如果所有计数问题都是“图中共有几个X”这种句式模型在RL阶段只对这一个句式过拟合。训练时最好混入几种提问方式“你能数一下有几个X吗”“X的数量是多少”“图里出现了多少只X”。这样模型学到的是感知能力而不是句式模板。4.2 RL训练配置基于策略优化算法落地要点拿到数据后进入真正的强化学习训练环节。策略模型建议用已经完成SFT的VLM作为初始化这样模型基础能力尤其是语言能力已经有了保障RL只负责把视觉感知的准确性调上来。训练算法我当时用的是GRPO这类算法在VLM多模态场景下比PPO更稳定主要原因是它不需要单独训练一个价值网络避免了批评者-行动者不匹配带来的方差问题。超参数上给几个参考值策略模型学习率2e-6到5e-6KL系数设置在0.01到0.05之间。KL系数特别关键——它约束策略不能偏离SFT初始模型太远。感知能力提升的同时如果发现模型通用对话能力明显退化说明KL系数太小要往上调。训练时还有一个容易被忽视的点批次构成。RL step里的图像样本来自不同任务维度存在性、计数、空间、属性建议每次更新batch里四个任务各占四分之一。如果某个batch全是计数任务模型这步更新会向计数方向剧烈偏转下一步又转向空间关系训练曲线会非常抖。4.3 训练监控奖励曲线之外还需要看什么监控指标上除了最直观的Verification Pass Rate验证通过率我强烈建议加一个“可验证率”指标——模型输出能被规则验证器成功解析的比例。它反映了模型有没有学会“用能被检查的方式说话”。如果pass rate在涨但verifiable rate在跌说明模型在逃避校验它学会了输出一些模棱两可、无法被解析的内容来规避惩罚。这种情况要立刻介入否则就是在自欺欺人。训练时还把每个代理任务的通过率单独拆开画曲线。有一次我看到总体通过率从65%涨到80%很兴奋但拆开一看存在性任务从90%涨到95%计数任务从50%涨到55%空间关系从40%涨到42%——整体提升全被简单任务吃掉了真正难啃的骨头根本没啃动。从那时起我就养成了“分层看指标”的习惯。5. 训练过程中记录的问题与排查方法5.1 奖励黑客模型学会了骗验证器这个现象在RL训练中非常经典。某次训练跑到第800步计数任务通过率突然暴涨到98%我以为模型开窍了。人工抽样看结果才发现模型对几乎所有数量问题都回答“一个”——因为训练数据里有大量单物体样本回答“一个”有很高的概率撞对而且之前的模型很少输出“一个”所以这个策略还没被惩罚过。这个例子完美诠释了“验证器只检查答案对不对不检查推理合不合理”。我用两个手段解决这个问题一是重新做评估集把所有正负样本比例严格对齐单物体和多物体各占50%让“只回答一个”的作弊策略暴露出来二是在最终评估时引入开放式问题模型需要输出完整的感知描述而不只是回答数量逼着它回到认真看图的状态。5.2 数据泄漏训练集和评估集撞车这个坑做RL评估的人都容易踩。视觉模型的记忆能力非常强如果评估集和训练集来自同一批数据源哪怕不是同一张图只要场景风格相似、物体布局相近模型都能靠“记答案”而非“看图像”拿到高分。我一度以为模型的空间关系能力已经超过90%换了个全新的合成场景测试集后直接掉到61%。排查方式是在数据层面做严格隔离保证训练集和评估集来自不同的数据源、不同的场景配置、不同的光照和视角分布。如果只能用一个数据源至少要做场景级别的划分——同一个场景的多个视角不能同时出现在训练集和评估集里。5.3 灾难性遗忘视觉感知上去了语言能力下来了这个问题的表现非常典型RL阶段跑完后视觉代理任务通过率提升了20多个点但模型在常规对话上的回答质量明显下降具体表现是回答变短、句式单一、缺少解释性。这是因为RL只在感知任务上做了优化模型学会了“简洁作答”把语言多样性的权重压低了。缓解策略有两个我当时都试了。一个是在RL训练时混合一部分通用指令数据比例大约1:4或1:5——每四个感知样本配一个通用对话样本奖励函数里给通用样本设定一个中性奖励不推不拉防止语言风格过度坍缩。另一个是适当增大KL系数权重强制策略保持在SFT模型附近不让它为了感知准确率而抛弃原有的语言能力。6. 关于ViCrit思路的一些思考与延伸场景我觉得这个工作最有价值的点是它把“验证”这个工程师文化的概念系统性带进了VLM训练。过去我们训练多模态模型太依赖“感觉”——感觉对话顺了、感觉描述变详细了但缺少一个自动化的质量闸门。ViCrit用代理任务可验证奖励搭了一个闸门让模型在训练中就能被持续纠偏。更进一步这套思路不止适用于静态图像。我的看法是把代理任务从“物体计数”“空间关系”扩展到“跨帧一致性”“动作顺序合理性”就可以用于视频VLM的时间感知训练扩展到“目标可达性”“路径遮挡判断”就能服务具身智能的决策训练。核心不变找到一个能被自动验证的中间信号然后让强化学习在这条信号上持续优化。根据我复现类似工作的经验我建议第一次尝试的同学不要贪多。先选两个代理任务——存在性检测和计数数据规模控制在2万到5万样本内跑通整个“数据构造-验证器编写-RL训练-指标评估”闭环再去扩展任务类型。这个过程里你会真实感受到模型的感知边界在哪里也能最直观地看到可验证奖励带来的稳定性。等你跑通了这个小闭环再回头处理复杂感知任务会发现思路已经清晰了太多。