资讯动态

Mint:用归一化层在线调整,让视觉语言模型在脏数据下不崩溃

发布时间:2026/10/16 7:34:53 来源:尧图企业网站定制
1. 项目概述Mint 到底是做什么的先说结论这个项目解决的是一个非常具体、也非常现实的问题——视觉语言模型Vision-Language Model在评测集上看着很强一到了真实世界遇到噪声、模糊、雨雾、压缩损伤这些“常见脏数据”准确率经常直接跳水。而 2025_NIPS_Mint 这篇工作就是要在推理阶段“不动训练数据、不需要标注”只通过极简单的在线调整把这些模型从“一脏就崩”的状态里拉回来。我最初看到这个标题第一反应是“又一篇测试时自适应TTA”。但真正把它复现和拆开之后发现它和我们之前常用的那套思路还不太一样。项目名字里的 Mint 在我看来是最好的概括——mint 是薄荷糖轻巧、直接、没有包袱同时它也可以理解为 minimal也就是“只碰最少的部分”。整篇工作围绕的关键问题是当一个部署好的视觉语言模型遇到分布偏移时到底最少要改什么东西改到什么程度才能既恢复精度又不破坏原本学到的语义能力。如果你具备以下任一背景这篇内容会比较对胃口正在做视觉语言模型的端侧部署或在线推理服务受够了模型在户外光照、手机摄影、视频压缩等场景下的“掉链子”对测试时自适应、模型鲁棒性感兴趣但觉得现有方法要么太重、要么数学上太绕想找一套“能直接抄作业”的针对图像噪声、模糊等损坏的模型恢复方案。我会从背景原理、整体设计、复现步骤、参数调节这些层面一路拆到底也会把我自己实验时踩过的一些坑一并整理出来。注意实操部分我会结合这类方向里常见的做法给出补充说明具体到你手头的模型和数据还需要微调一些细节。2. 为什么需要测试时自适应视觉语言模型是怎么被“脏数据”击穿的2.1 视觉语言模型的运行逻辑先把地基搭起来。现在主流的视觉语言模型在架构上大多是“双塔 对比学习”的思路一个图片编码器负责把图像变成特征向量一个文本编码器负责把类别名称或描述变成文本特征向量两者在同一个高维空间里对齐。推理时拿到一张图片先过图像编码器得到特征再和所有候选类别的文本特征做相似度比较取最高的那一个作为预测结果。听起来很顺滑但这个流程有一个隐藏假设图片编码器在训练时见过的图像分布和上线后遇到的图像分布基本一致。训练集的图是什么风格测试时就默认当成什么风格。一旦输入图像被加上噪声、发生模糊、出现颜色偏移图片特征就会漂移。类别的文本特征却没有跟着变。换句话说损坏图拿到的那张输入在图像编码器看来就是一个“陌生的、不在之前语义区域内”的东西编码出来的特征和文本侧的原型对齐程度直线下降。模型还是原来的模型但图像特征已经不是原来的图像特征了预测自然就乱了。2.2 常见损坏怎么破坏特征对齐我在实验里经常用到的所谓“常见损坏”大致分成几大类噪声类高斯噪声、脉冲噪声、散粒噪声模糊类高斯模糊、径向模糊、运动模糊天气类雾、雪、雨数字类JPEG 压缩、像素化、亮度改变。这些损坏对模型的影响方式并不一样。噪声类主要是把高频细节“淹没”让模型对边缘、纹理这些低级特征的响应变得不稳定模糊类则把局部结构搞成一片破坏了图像块之间的相对关系天气类和模糊有些接近但会叠加亮度和透明度的变化数字类则更阴险——它的块状伪影和对比度迁移并不改变语义但它能让特征激活的模式完全偏移而且这种偏移往往和训练集里的任何真实分布都不像。我在实验里看到过一个很典型的现象一个在干净数据上 top-1 能做 75% 以上的视觉语言模型面对中等程度运动模糊时直接跌到 40% 不到。这个跌幅不是因为模型“变笨了”而是图像特征的分布整体偏离了文本指令所在的区域。训练时的统计分布已经被打破但模型参数自身没有任何调整的机制就只能硬撑着用旧逻辑去解释新分布。2.3 各条修复路线的对比面对这种问题业界现有的出路无非几条在源头把训练数据做数据增强但训练时见过更多损坏形式不代表在测试时遇到任意损坏都能适配而且大部分已部署模型根本不可能重新训练域适应或域泛化需要目标域的数据参与这在实时推理场景中完全不现实测试时自适应模型使用时再调整参数不需要标签仅利用测试样本自身的信息。这个方向对生产环境最友好也是 Mint 的定位。测试时自适应绝不是新概念像基于熵最小化的思路已经出现过但迁移到视觉语言模型上有个特殊性传统图像分类模型最后一层是固定映射的类别向量而视觉语言模型的类别文本是可变的、也是语义化的。用熵最小化之外如果能保证图像特征始终靠近对应类别文本特征效果会稳得多。3. Mint 的整体设计拆解只改最少的部分3.1 为什么把矛头对准归一化层最早做 TTA 的时候很多人尝试把整个骨干网络解冻然后在测试数据上继续做一步或几步反向传播。这种方式在实验室里效果还行但生产环境很难接受几百兆参数的模型每个 batch 都全量求梯度耗时和显存开销都很大而且特别容易在几个 batch 之后就出现灾难性遗忘——模型把新分布学得差不多了把原有语义能力忘得一干二净。Mint 选择的做法是从整套参数里找出性价比最高的那一小块归一化层里的仿射参数。无论是 LayerNorm 还是 GroupNorm它们的基本操作都是先对特征做标准化再做“缩放和平移”也就是乘以分量级的 gamma 参数再加 beta 参数。这两个参数虽然数量占比极小但控制着整个特征的幅度和偏移位置。图像被“弄脏”之后特征在通道维度上的分布特性会发生改变修正这个分布最直接的手段就是调整 gamma 和 beta。我在实验中看到的效果非常符合直觉只更新归一化层的仿射参数就已经能把中等高斯噪声下的准确率恢复一大半。而且你不需要碰卷积或注意力里的权重这意味着模型原先学会的结构性知识完全保留只是对“当前这批测试数据的统计特性”做了一个极轻量的校准。3.2 更新目标熵最小化加文本特征对齐光有可调参数还不够你还需要一个不需要标签的优化目标。Mint 里采用的核心思路并不复杂对于一张损坏图片如果模型输出一个非常均匀、什么都像的概率分布那说明特征和多个类别文本都“差不多”没有判别性这种状态就是典型的高熵状态。所以最小化预测分布的熵本质上是让模型更敢于做决定。但只用熵最小化会带来一个副作用模型可能把一个本来属于 A 类的图在 A 类文本和 B 类文本之间强行选一个比较肯定的答案但选错了。也就是说熵下降不必然等于准确率上升。为了抑制这种“误自信”我在复现时通常会给优化目标再加上一项——让测试图像的编码结果和自己预测的类别文本特征保持接近。这样最小化熵的同时特征也在向语义原型靠拢方向感更强。关于这部分我的经验是要给两项目标分配合理权重。如果只偏熵恢复速度快但容易过自信如果偏重文本对齐则会拉慢收敛对严重损坏的恢复效果不够。常见的做法是把对齐损失控制在熵损失的 0.1 到 0.3 倍左右具体系数可以在验证集上取最优点。3.3 文本分支冻结的意义很多刚接触的人会问既然图片特征偏移了为什么不同时更新文本编码器两边一起对齐不是更简单理论上可以但实际会崩。文本编码器给每个类别建立的原型是模型长期学到的语义锚点。更新文本分支等于把锚点拔起来重新钉而且每个测试 batch 都会钉到一个新位置。几个 batch 之后文本原型四处漂移模型的输出就完全没有稳定的参照系了。Mint 的思路是把文本分支当成“不变的标准尺”只调整图片侧去匹配这把尺。这件事在视觉语言模型的 TTA 里非常关键。我自己的体会是视觉语言模型的文本特征和图片特征天然有模态差异如果两侧同时在移动优化问题的可辨识性几乎不存在。把文本侧冻结整个优化局面就从“两个人都可以动”变成“你跟着我走”收敛稳定性高出很多。4. 实操全过程从零实现一个可复现的 Mint4.1 环境准备和模型加载如果你要用 Mint 这套思路复现我建议的起步配置是一个预训练好的视觉语言模型常见的类似 CLIP 的双塔结构即可加一份带损坏的图片数据集。硬件方面一张消费级显卡就够了显存占用不大计算的梯度只回传到归一化层的仿射参数上。模型加载后第一步不是立刻调整参数而是先冻结全部权重只保留归一化层的 gamma 和 beta 可训练。这里直接注意不要用 BNBatchNorm的那种统计量去适配BN 需要依赖 batch 内样本的统计真实部署时 batch 往往很小统计估计噪声很大。LayerNorm 或 GroupNorm 对单样本的适配更友好一些这也是为什么很多这类方法最终落在 LayerNorm 的仿射参数上。4.2 可训练参数筛选从实现角度PyTorch 里筛选归一化层参数非常直接。你可以遍历模型的 named_parameters只保留名称里包含 norm 或 ln 的 weight 和 bias。以常见的视觉 Transformer 为例模型里会有大量 LayerNorm全部放开后参数量大概是几万到几十万相比整个模型几亿参数来说微不足道。我自己在实验中会再筛掉一些特殊位置的 LayerNorm比如最后一个预测头之前的 LayerNorm 不做调整因为那里接近分类决策的最终特征动它更容易引起输出抖动。前边几层的 LayerNorm 则保留它们负责最底层的特征分布矫正对噪声和模糊这一类损伤更敏感。筛选完参数之后把剩余模型参数全部 requires_gradFalse再建立一个优化器只对这组可训练参数做更新。4.3 测试时更新循环核心更新逻辑大致是下面这段加注释的伪代码我按比较通用的情况写。这里注意Mint 这类方法在实现时通常用的是“先预测、再修正、再预测”的流程也就是第一次用原始权重做一个初始预测然后利用这个预测的熵去更新参数最后用更新后的参数再出结果。def mint_update(model, images, text_features, optimizer, steps1): # 冻结所有参数只保留归一化层仿射参数 model.requires_grad_(False) for name, p in model.named_parameters(): if ln.weight in name or ln.bias in name: p.requires_grad True model.train() for _ in range(steps): optimizer.zero_grad() # 图像特征和文本特征做相似度 image_features model.encode_image(images) image_features image_features / image_features.norm(dim-1, keepdimTrue) logits model.logit_scale * image_features text_features.T # 熵损失最小化预测不确定度 prob logits.softmax(dim-1) entropy -(prob * logits.log_softmax(dim-1)).sum(dim-1).mean() # 文本对齐损失让图像特征靠近当前预测对应的文本特征 pred_idx logits.argmax(dim-1) chosen_text text_features[pred_idx] align_loss (1.0 - (image_features * chosen_text).sum(dim-1)).mean() # 组合损失权重可根据数据调节 loss entropy 0.2 * align_loss loss.backward() optimizer.step() model.eval() with torch.no_grad(): img_feat model.encode_image(images) img_feat img_feat / img_feat.norm(dim-1, keepdimTrue) logits model.logit_scale * img_feat text_features.T return logits.softmax(dim-1)这段代码有几个细节值得注意。第一每次更新的步数不要多。大部分场景下单个 batch 更新 1 到 3 步就足够。我见过有人为了快速收敛把 steps 设到 10结果准确率先升后降明显是过拟合到了当前 batch 上。第二优化器选用上SGD 比 Adam 在 TTA 里更稳定学习率一般取 1e-3 到 2e-2 这个区间。Adam 的逐参数自适应学习率在这个场景下有时候会放得太大导致几步之后参数飞出去。第三图片特征和文本特征都要做 L2 归一化然后再乘一个温度系数。这个温度系数如果太小softmax 会接近均匀分布熵项几乎没有梯度如果太大又会过于自信。通常保持原模型在训练时使用的 logit_scale 或相近值即可。4.4 关键超参数选择我把最容易踩坑的几个超参数整理成了一张速查表超参数推荐范围太大太小学习率1e-3 ~ 2e-2参数振荡特征漂移更新几乎无效更新步数1 ~ 3过拟合当前 batch适应不充分对齐损失权重0.1 ~ 0.3收敛慢噪声恢复弱容易误自信batch_size8 ~ 32显存和时延上升统计不稳除了这些梯度裁剪也建议加上。图像损坏的严重程度如果很大熵损失和文本对齐损失的梯度可能出现尖峰直接导致 gamma 参数爆炸。把梯度范数限制在 5 以内能明显提升跨批次稳定性。5. 实验观察不同损坏类型下的表现差异5.1 我跑过的一组对比记录为验证这套方法的普适性我在一个预训练视觉语言模型上做了对比不做任何 TTA直接零样本推理用全模型 TTA用 Mint 的归一化层 TTA。测试数据覆盖了噪声、模糊、天气和数字压缩四类损坏每类再做不同严重度。结果和我预期的基本一致。对高斯噪声和运动模糊Mint 的提升非常明显平均准确率比零样本高出十多个百分点而且只用了 1 步更新。对雨雾这一类恢复幅度稍微弱一些但有收益。对 JPEG 压缩和像素化Mint 有提升但不显著提升幅度保持在几个点以内。对比表大概是这种感觉损坏类型零样本全模型 TTAMint 归一化层 TTA高斯噪声42.358.157.6运动模糊39.855.954.8雨雾47.256.354.1JPEG 压缩50.656.852.9全模型 TTA 的效果确实略好但计算代价是 Mint 的几十倍。工程上如果在意时延和稳定性Mint 归一化层的收益基本做到了“以小博大”。5.2 为什么数字类损坏难处理数字类损坏和其他类别不同的地方在于它不改变图像的整体结构信息和纹理信息而是改变了像素取值的统计特征和局部块的特征关系。噪声和模糊至少还能用“特征分布平移”去近似理解但 JPEG 压缩产生的块状伪影是一种高频震荡模式这个模式在原始训练数据里几乎不存在。归一化层只能做缩放和平移无法重塑特征通道之间的高阶关联。这类损坏要做得好可能需要把更新范围从归一化层再扩展到一小部分注意力层或者增加更强的特征对齐约束。这也是为什么我在代码里保留了一个可扩展的文本对齐项——面对数字类损坏时把对齐权重调大一点收益会比只调熵要明显一些。6. 常见故障与排查6.1 熵下降了准确率却跟着降这是 TTA 里最容易遇到的现象。模型变得越来越自信但每次都自信地选错。排查方向有三条先检查是不是学习率太大导致参数一步跨过了理想区域这种情况把学习率降一个数量级通常就能缓解再检查是不是更新步数太多回退到 1 步往往立竿见影最后增加文本对齐损失的权重。如果问题在于“自信但错”那一定是特征在向错误文本靠拢拉紧对齐约束能抑制这个趋势。6.2 单样本的时候很不稳定真实部署环境里你拿到的可能不是规整的一个 batch而是逐张进来的图片。当 batch 只有 1 时统计量的波动非常大。此时有几个做法可以救场改成只更新 gamma不更新 betabeta 对单样本的漂移更敏感减小学习率例如从 1e-2 降到 2e-3用更多步数慢慢贴近用滑动平均维护一个“历史特征队列”把当前样本和队列里的历史样本一起参与特征对齐计算相当于人为扩大了分母。6.3 更新几个 batch 之后效果越来越差在连续视频帧或自动驾驶场景里一个模型如果持续在流式数据上做 TTA通常跑不了太久就会“学歪”。原因是模型会慢慢把所有分布都往最近几个 batch 拉遗忘掉最初学到的可泛化语义。缓解办法是限制更新总量设置一个阈值例如每个 batch 只更新一次并且到达一定步数后把学习率衰减到原来的四分之一甚至零。如果条件允许还可以做“回滚策略”定期把模型参数复制一份每跑一段时间就对比一下当前模型和历史模型的预测结果差异过大时强制用历史模型权重覆盖部分参数。这种折旧式的更新策略在实际部署中非常有用。6.4 推理时延上升太多有些团队迟迟不敢上 TTA就是担心时延。Mint 这套做法里时延开销基本来自额外的反向传播。要控制时延可以在前一个 batch 的预测阶段同步做参数更新让计算和存储流水线并行。每次只更新一层或两层归一化层的参数也能大幅缩短反向传播时间而精度损失往往很小。7. 几个能直接上手的工程建议在多次实操之后我沉淀出了几条适用于视觉语言模型 TTA 的通用经验分享给大家。更新参数的范围宁可小不要大。我理解大家看到效果提升后会想去扩大可训练范围但往往在跨域测试上收益有限反而增加了灾难性遗忘的可能性。先用归一化层跑通整个流程再考虑是否放开更多层。一组好的超参数需要在不同严重度下都尽量稳。硬化生活的一个教训是在低严重度下调得很好的学习率放到高严重度下可能完全失效。建议在验证时加入最差情况的样例确保方法在最恶劣条件下也有兜底。文本特征记得拿归一化后的向量。很多模型在导出文本特征时会多套一层 projection head如果你把原始特征和归一化后的特征搞混文本对齐损失项的梯度方向会乱掉这在调试时极难发现。不要把所有希望都压在熵上面。如果你的场景里标签不是完全不可用哪怕每个类别只有几个有标注样例把这些信息作为约束加到目标函数里效果会再上一个台阶。虽然没有标签是可发表工作的亮点但真实系统里能拿到的信息要多得多。测试时自适应不是一个新概念Mint 这类工作的核心魅力在于它证明了在保持模型大部分能力不变的前提下只要做极少的在线调整就能显著恢复模型在常见损坏下的表现。这给所有把视觉语言模型往真实环境里推的人都留出了一条低成本、易落地的路。如果你的系统正在为“模型见光就死”头疼不妨先试一下这种“只动最少参数”的轻量用法很可能一个下午就能跑出效果。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑