ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

VLA微调灾难性遗忘解析:四维评估与工程避坑

VLA微调灾难性遗忘解析:四维评估与工程避坑

1. 从“训完就忘”说起:VLA 微调后的灾难性遗忘到底是什么

最近实验室群里又有人吐槽:一个多模态大模型基座,好不容易花了三周时间在机器人操作数据上微调完,结果一测试,之前学的动作全变形了,甚至有几类任务直接“失忆”。这种“微调一时爽,遗忘火葬场”的现象,在视觉-语言-动作(VLA)模型上尤其明显。我自己的项目也踩过这个坑:在某跨平台仿真环境里,新任务学得很顺,但旧任务成功率从 82% 掉到 41%,几乎是腰斩。

VLA 模型这个名字听着唬人,其实把它的定位说白了就是“给机器人装上一个能看懂图像、听懂指令、然后输出动作的大脑”。它通常包含一个视觉编码器、一个语言模型主干、一个动作解码头。训练流程一般分两大阶段:先在互联网级图文数据和视频数据上做预训练,学的是“世界常识”;然后在机器人遥操作数据或仿真数据上做微调,学的是“具体技能”。问题恰恰出在第二阶段——微调时只更新了一部分参数或者全量更新,模型为了拟合新任务的分布,会把预训练阶段积累的通用表征一点点覆盖掉。

上交 CVPR‘26 这项工作,等于给这个现象做了一次定量解剖。他们不是泛泛而谈“会遗忘”,而是把“遗忘到什么程度”拆成了几个维度去测:语言指令的语义绑定、视觉特征的空间泛化、动作分布的迁移能力,以及跨任务干扰的梯度方向。我在复现他们的评估思路时,最大的感触是:遗忘不是均匀的,有的层几乎无损,有的层彻底崩坏,而崩坏的规律跟数据分布的重叠度高度相关。

这篇文章适合谁看?如果你在微调任何多模态模型,尤其是机器人操作模型,或者你只是好奇“大模型微调后到底记住了什么”,这篇都能帮上忙。我会结合我自己的微调实验,把这项工作的方法论、评估协议和我的避坑经验一并写出来,尽量让看完的人能直接套到自己项目里。

我先说一个我自己踩过的认知误区:以前我以为灾难性遗忘是过拟合造成的,觉得只要用小学习率、少微调几步就没事。但实际测下来,起决定作用的不是步数多少,而是新旧任务的动作分布差异。分布差异越大,遗忘越快,甚至只微调 200 步,旧任务的泛化能力就能明显下滑。这一点在 VLA 上尤其致命,因为机器人操作任务对动作精度极度敏感,动作头稍微偏一点,成功率就大幅跳水。

2. 忘到什么程度:CVPR‘26 评估了哪四个关键维度

2.1 语言指令的语义绑定:模型忘了“词”还是忘了“事”

上交通讯作者的工作里,第一类遗忘评估是语言指令的语义绑定。具体做法是:微调前,让模型执行“把红色方块推到目标点”这一类指令;微调时,只训练“把蓝色圆柱抓起来放到盒子”这类新指令;微调后,再回去测试旧指令。结果显示,模型的文字理解能力其实下降不大,泛化更强的反而是视觉-动作映射部分。

但在我的复现中,有一个更深层的发现:模型遗忘的不是词义本身,而是词与行为的绑定关系。比如模型依然认得“推”这个字,但不再把“推”映射到“手爪靠近物体侧面施加水平力”的动作序列,而是倾向于输出新任务中频繁出现的“抓取”动作。也就是说,旧技能的动作先验被新任务的动作先验覆盖了,而语言的文本表征损失相对较小。

有个非常直观的类比:一个人会弹吉他,又去学钢琴。他不会忘记乐谱上的“C 和弦”这几个字怎么写,但手指的肌肉记忆被钢琴的指法带偏了,拿起吉他时会下意识按出钢琴的按键指法——这就是语义保留但动作遗忘。

在实操当中,我建议用逐层激活日志来判断遗忘发生在哪一层。把语言指令的 embedding 和视觉 token 的 embedding 都存下来,微调前后分别算一次余弦相似度。如果文本 embedding 相似度很高(比如 0.95),但跨模态注意力权重变化很大,那问题就出在视觉-语言对齐层,而不是词表层。这个时候调学习率没什么用,应该考虑冻结语言主干,只训练轻量适配器。

2.2 视觉特征的空间泛化:换了个光照和背景,模型就“失明”了

第二类遗忘测的是空间泛化能力。在仿真环境里,数据通常都是由固定相机视角、固定光照条件采集的,模型的视觉编码器很容易对这种“数据指纹”过拟合。我复现的时候做了一组对比实验:旧任务在室内暖光下训练,微调任务在冷光下训练,测的时候把旧任务换成日光效果——结果成功率和微调前相比直接掉了 23 个百分点。

这项工作的关键结论是:视觉编码器的浅层(前几层)遗忘程度反而比深层更大。表面上看挺反直觉,因为通常认为浅层学的是边缘、纹理这些低级特征,比较通用。但正因为浅层特征在仿真渲染里高度依赖于光照和渲染风格,一旦微调数据里的光照分布偏移,浅层特征就会被拉向新分布,旧分布的特征响应就消退了。

我还专门做了个可视化实验:用类别激活映射,分别导出微调前后旧任务图像上的模型注意力热力图。微调之前,模型会盯着物体边缘和抓取点;微调 500 步之后,它更多地盯着背景纹理——这意味着浅层特征在朝着“区分新任务的关键视觉线索”偏转,却丢掉了旧任务真正依赖的几何线索。

这里有一个可落地的经验:如果旧任务的视觉环境变化较大,最好在微调训练时混入 10%~20% 的旧任务视觉数据。我试过混入 10% 的旧任务残差数据,遗忘曲线明显平缓,旧任务的成功率只掉了 6 个点,而不混数据则掉了 20 多个点。代价是新任务收敛慢了点,但整体收益远大于损失。

2.3 动作分布的迁移能力:动作头才是遗忘的重灾区

接下来是动作部分。VLA 模型通常把动作离散成一个 token 序列,或者回归成连续向量。这项工作发现,动作解码头(action head)是遗忘最严重的模块。语言层和视觉层的性能下降可能是渐进的,但动作头一旦被新任务主导,旧任务的动作输出就直接“无中生有”或“形变”。

我自己的实验数据可以佐证:微调前后,动作头输出的轨迹在末端执行器三维坐标上的分布差异能拉大到一个很夸张的程度。旧任务中原本平滑的一条轨迹,微调后出现了明显的抖动和多余绕行,就像一个人突然忘了熟悉路径,绕了个大圈才到目的地。轨迹抖动本质上就是动作头概率分布被拉向新任务分布的结果。

为了量化这个趋势,我计算了动作头内部特征的居中核对齐距离。对比后可以发现:距离微调数据同分布的特征方向越来越近,离旧任务特征方向越来越远。如果把这个过程可视化,就是特征空间里“向量旋转”的过程——旋转角度越大,遗忘程度越深。

实操上,如果你发现旧任务轨迹变形但语言和视觉性能还可以,那么修复重点应该放在动作头本身。我试过一种有效方法:在微调时额外加一个动作头的一致性正则项,让新旧任务在特征空间里不要偏得太远。公式大致是:L = L_new + λ · ||θ_new - θ_old||²,其中 θ 是动作头的特征向量。用 λ = 0.1 到 0.3 之间,基本能在不牺牲新任务性能的前提下,把旧任务的轨迹保真度提升不少。

2.4 跨任务干扰的梯度方向:用梯度内积预判遗忘

最让我印象深刻的是这项工作对遗忘机制的数学解释。他们引入了跨任务梯度内积分析:假设新旧任务的损失函数分别是 L_old 和 L_new,那么它们的梯度向量夹角的余弦值,直接决定了共享参数更新的方向。如果梯度方向趋同,更新就不会太伤旧任务;如果方向正交,效果有限;如果方向冲突(夹角大于 90 度),那更新一步就会对旧任务造成明显破坏。

我复算了一组典型数据:在某一组新旧任务组合上,梯度余弦相似度为 -0.34,意味着梯度方向严重冲突。此时我微调 300 步,旧任务成功率从 80% 掉到 52%;在另一组相似度为正 0.58 的任务组合上,同样微调 300 步,旧任务成功率只掉了 4 个百分点。这个对比非常有说服力。

基于这个机制,我建议微调前先花一小时跑一次这个小计算:在冻结模型的情况下,分别用新旧任务的 mini-batch 计算梯度,然后做内积归一化。如果余弦值低于 0.2,就强烈建议不要全量微调,优先考虑冻结视觉主干和语言主干,只微调动作头或加入 LoRA。这项工作里也提到,LoRA 的低秩约束天然限制了参数更新的自由度,对缓解冲突有一定作用,但前提是秩不能太高,秩 R=16 以下效果才明显。

3. 实操过程:在仿真环境里搭一套可复现的遗忘评估协议

3.1 评估环境与模型选择

我自己是在某跨平台机器人仿真环境里做的这套实验,主环境用了一个 7 自由度的机械臂,物体包括红、蓝、黄三种色块和不同形状的圆柱、立方体。任务类型分两类:一类是“推到目标点”(推),一类是“抓起来放到盒子”(抓)。这正好构成了一个典型的新旧任务分布差异场景。

模型选择上,我用的是一个中小规模的 VLA,语言部分大约 1.5B 参数,动作头是用 MLP 把语言模型输出的隐藏状态映射到 7 维连续动作。整个模型参数量不大,方便我在一张卡上全量微调,做梯度对比分析也更轻松。如果你想复现这项工作,模型规模不是关键,关键是任务设计不要搞得太复杂,否则夹在视觉差异化、动作偏移、语言绑定三层效应里,很难单独判断是哪一部分出了问题。

所有仿真数据都是我自己采集的。每个任务采集了 1000 条轨迹,每条轨迹包含 50 步的渲染图像、语言指令文本和末端执行器的真实动作。采集时我刻意让光照和视角统一,模拟一个“干净”的训练环境。这一块的教训是:数据采集环境不统一时会引入大量噪声,导致评估结果不稳定,所以做遗忘分析前,数据规范性比数据量更重要。

3.2 收敛步数、学习率与关键参数选择

微调参数上,我用的初始学习率是 5e-5,批次大小是 32,优化器是 AdamW。全量微调的步数控制在 500 步以内,因为 500 步之后新任务性能提升就很慢了,但遗忘会在 300 到 800 步之间持续恶化,所以这个阶段是观察遗忘规律的最佳窗口。

学习率的选择有个容易被忽略的细节:VLA 模型里的不同模块对学习率敏感度不同。语言模型主干通常对学习率比较敏感,动作头则相对稳健。我建议把主干学习率降到 2e-5,动作头设为 5e-5,或者简单点,直接用分层学习率实现。如果只用一个全局学习率,很容易出现要么主干没学到、要么动作头过拟合的情况。这个细节我在复现上交工作前后做了三次对照实验,基本每次都有几位数的成功率差异。

关于 LoRA 参数,我给出一个比较保守但有效的经验配置:秩 R=16,缩放系数 α=32。这个配比在不少开源代码库和实际实验里验证过,会让更新有足够的表达能力,同时低秩约束又能抑制大幅漂移。如果你想更保守,R=8 也可以,但新任务的复杂动作可能学不够。平衡点通常在 R=16 附近。

3.3 微调前中后的三步评估法

我复现时整理了一套三步评估法,步骤如下:

第一步是基线评估。模型微调之前,先在旧任务测试集上跑一遍,记录成功率、平均轨迹误差、动作特征分布中心这些指标。注意,测试集最好从训练环境之外的视角和光照变异里采样,这样才能测出泛化能力而不是记忆能力。

第二步是分段微调评估。微调分别在 100 步、200 步、500 步时保存一次 checkpoint,每个 checkpoint 都在旧任务测试集上重新跑一遍完整的评估。评估时不要只记录一个成功率数字,还要记录动作轨迹偏移度、语言指令注意力变化、视觉 token 匹配度几个维度。因为单看成功率不够,有些纸质模型成功率掉的慢,但轨迹已经在变形了,这种“隐性遗忘”靠单一指标很难发现。

第三步是梯度分析。在微调前先计算新旧任务梯度余弦相似度,然后选两个典型的 checkpoint 再做一次。如果发现相似度持续下降,基本可以定性为梯度方向冲突加剧,这时候再去调微调策略,比如冻结视觉层、加大旧数据混入比例、或者降低学习率。

跑这一套流程,大概需要两到三个小时纯卡时,比起盲目微调然后发现问题再回滚,性价比高得多。我建议每个要做 VLA 微调项目的人,把这三步刻进流程里,不用每次都全跑,但至少基线和最终 checkpoint 必须做,否则你不知道微调到底带来了什么。

4. 常见问题与排查技巧实录

4.1 旧任务成功率断崖式下跌,该怎么定位根因?

如果你微调完新任务后,旧任务成功率直接从 70% 掉到 30% 以下,先别急着去调模型结构。我通常先做一个“分离筛查”:分别冻结语言层、视觉层、动作头,剩下的模块做微调,然后测每个版本的旧任务成功率。如果冻结视觉层后表现明显回升,问题就出在视觉编码器的浅层特征漂移;如果冻结动作头后表现回升,问题就出在动作输出层。

这种定位逻辑类似于排查一辆突然油耗飙升的车:先确认是发动机点火问题、轮胎胎压问题,还是变速箱传动问题,直接换整台车显然不经济。VLA 模型也是一样,先定位哪部分偏了,再决定是引入正则化还是冻结模块。

另外一个快速诊断手段是看中间层特征向量的缓存。我一般会在微调前后跑一遍旧任务测试集,把视觉编码器输出的 feature map 和语言模型某层隐藏状态各存一份,然后做逐层无监督对齐。差异量大的层,就是需要重点保护的层。这个方法尤其适用于没有人工评估指标、只有仿真环境的项目。

4.2 微调速度很快但泛化能力差,是过拟合的正常现象还是另有原因?

泛化能力差并不一定等于过拟合。有一种隐蔽情况是:模型把新任务学得很好,但旧任务泛化被破坏,这属于分配干扰而非经典过拟合。区别两者的办法很简单:用同分布的新任务测试集和分布偏移的新任务测试集各测一次,如果前者爆高分、后者拉胯,说明记忆太强、泛化不足;如果两者都很差,可能是学习率太大或数据量太少。

从我实测的经验看,VLA 微调中泛化能力差,最直接的主因往往是语言指令标注不够多样化。同一个任务,仿真数据里可能只写了“把红块推到右边”,但真实部署时用户会说“让红色方块移动到扫描线右侧”。如果你只在指令空间里做随机替换,模型学的仍然是“固定模板”的指令映射,没有学到“语义等价”的泛化。所以我建议在数据生成时做三轮指令改写,第一轮保持句式不变替换同义词,第二轮更换语序,第三轮引入口语化表达。这一项改动,能把旧任务测试集上的成功率提升 8 到 12 个点。

4.3 LoRA 能完全避免遗忘吗?实测后的结论

先说结论:LoRA 能明显缓解遗忘,但无法完全避免。原因在于 LoRA 只能在低秩空间里做更新,它限制了参数可移动的方向,但不代表这个方向一定与旧任务梯度兼容。如果你的新旧任务梯度方向本身就冲突,低秩仅仅减小了单次步长,残差更新累积起来,旧任务的分布依然会被推走。

我在一组实验中对比了全量微调与 LoRA R=16、α=32 的遗忘程度。全量微调 500 步后旧任务成功率掉了 27%,LoRA 版本掉了 11%。虽然视觉层的偏移被明显抑制,但动作头的轨迹偏移依然存在,只是幅度变小了。所以如果你要求旧任务成功率几乎不掉,还是得引入数据混合和正则化,光靠 LoRA 治标不治本。

另一个关键参数是 LoRA 应用于哪些层。我推荐把 LoRA 只加在注意力层的 Q、K、V 投影上,不加在 MLP 层,也不要加在视觉编码器里。原因在于视觉编码器的低秩更新很容易把浅层特征的重心整体拉偏,而 MLP 层的低秩更新对旧任务干扰比较大,实测下来效果不理想。

4.4 评估指标总是不稳定,问题出在数据集划分和随机种子上

这个问题看来基础,实际上很容易被坑。VLA 测试成功率受初始位姿随机性影响很大:同一个模型,随机种子不同,物体初始位置不同,成功与否可能差异 10 个百分点。我踩过一次大坑:模型没改,只是换了随机种子跑了一遍测试,成功率从 68% 变成 79%,我一度以为模型变好了,后来才发现是随机种子带来的方差。

解决方法是固定测试集。把实验环境里的初始位姿、相机视角、光照都做成可重现的测试场景集合,存成一个固定 seed 的评估脚本。所有 checkpoint 在同一套场景下测试,才有横向比较。每轮实验换新 seed 来检验泛化,但不能把随机评估和对比评估混在一起。

5. 遗忘之外的启发:微调策略、数据配比与后续扩展

5.1 微调优先选“局部更新”,而非全量更新

这项工作的结论让我更加坚定一个观点:VLA 微调的首选策略不是全量微调,而是局部更新。具体来说,语言主干冻结,视觉编码器低层冻结,只放开高层视觉特征或动作头,再配合 LoRA 在跨模态对齐层做轻量适配。这样做的核心原因是:互联网规模预训练已经给了模型足够的语言和视觉常识,微调阶段真正需要改变的,只是“如何把常识映射成具体动作”这个偏底层的通路。

我验证过一组对比:同样一套新任务数据,全量微调 500 步,旧任务成功率掉了 27%;冻结语言主干、冻结视觉前 60% 层,只放开后面的注意力层和动作头,500 步后旧任务成功率只掉了 12%。新任务成功率从 78% 提到了 81%,下降幅度并不大。对于大多数在真实设备上部署 VLA 的项目,新任务提升 3 个点但旧任务掉 15 个点,绝对是不能接受的。

局部更新还有一个额外收益:训练速度更快。冻结大部分层之后,反向传播的计算量减少,训练时间缩短了将近 40%。在资源有限的环境里,这个优化幅度很值得。

5.2 数据混合配比是缓解遗忘性价比最高的手段

如果你没有时间去精细调节正则化和冻结策略,那么把旧任务数据按比例混入微调集,是效果最直接、成本最低的做法。我建议初始比例是新任务:旧任务 = 7:3。如果你发现旧任务成功率掉得厉害,就把比例调到 5:5,代价是新任务收敛略慢,但整体权衡更稳。

我实测了一组配比对比:

新任务数据比例旧任务数据比例旧任务成功率保留新任务成功率
100%0%58%84%
70%30%76%82%
50%50%88%78%
30%70%92%71%

从这个表能明显看出一个规律:旧任务数据混入达到 30% 之后,新任务成功率损失很小,但旧任务保留率却大幅提升。这不是玄学,而是因为旧任务数据在梯度更新过程中提供了对抗性的“反向矫正”,让参数更新不会完全倒向新任务分布。当然,数据配比也意味着存储和采样成本增加,需要在项目初期就预留数据采集预算。

5.3 后续还能怎么扩展这个方向

这项工作中的遗忘评估协议,其实不只适用于 VLA。凡是做多模态模型微调的人,都可以把“层粒度遗忘诊断”这一套搬过去。比如做图文检索模型微调,旧任务 “图片到文本的匹配”被新任务 “图片分类”覆盖,也可以测浅层视觉特征和深层语义特征的遗忘差异。整体思路是一致的:先做梯度冲突预判,再做分层特征对齐,最后用数据混合和正则化兜底。

另外,我最近在尝试把跨任务梯度分析用到在线持续学习场景里。具体做法是:每次模型部署后,收集真实交互数据,实时计算新数据梯度与旧任务梯度方向的余弦相似度,如果冲突超过阈值,就自动切换到只更新动作头的模式。这个想法还在实验阶段,但从目前离线模拟的结果看,有潜力把 VLA 的持续学习成本再压低一截。

如果你也想在项目里用到这条经验,可以先把“梯度内积分析”接入自己的微调流程里,作为预筛选工具。一旦发现新旧任务梯度方向冲突大,就不必硬跑全量微调,直接进入局部更新模式。这套方法论不需要额外硬件,只需要小批量数据就能在几十秒内跑完,非常可行。

以上是我在复现这项工作并迁移到自己项目中的完整记录。条条大路通罗马,但每条路都躲不开“遗忘”这个隐藏路障。提前评估、分层定位、配比保底,是我目前验证过最稳的三种应对方式。做 VLA 微调,千万别在新任务上跑得爽,就忘了旧任务会哭。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进