尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

当模型学会你教的一切:数据泄漏、微调与蒸馏排查指南

当模型学会你教的一切:数据泄漏、微调与蒸馏排查指南 上周有个朋友半夜发消息给我说他们团队训了一个客服意图分类的模型验证集准确率从 82% 干到 94%老板当场批了下一阶段的预算。结果灰度上线第三天线上真实流量的准确率只有 79%比改版之前还低一个点。他把训练日志、数据清单、超参配置全发过来我翻了半小时就找到了病根他们做数据增强时用同一个模板批量生成了几百条样本又按 8:2 随机切分成训练集和验证集同一个模板的不同变体同时落在两边。模型没学会意图它学会了那个模板长什么样。当模型学会了你教它的一切这句话我越想越觉得它是一枚硬币的两面。正面是模型极强的拟合能力——只要你给的信号足够一致它几乎不会漏掉反面是它忠实地把你数据里的捷径、偏见、脏标注、甚至评测集的答案一并打包带走。问题从来不是模型学不会而是你教的东西未必是你以为你教的东西。这篇就围绕这件事展开聊聊怎么判断一个模型到底是学会了规律还是背会了答案以及微调、蒸馏、量化这几个环节里哪些操作会把照单全收这件事放大。1. 模型这个词先要对齐它学的是参数不是你的意图1.1 三种被统称为模型的东西我在跨团队沟通里最常遇到的摩擦不是技术分歧而是模型这个词压根不是一回事。做后端的同事说模型指的是 JVM 内存模型那是一套规范定义的内存可见性与指令重排约束做电气设计的同事说模型指的是 EPlan 图纸里的端子模型本质是可复用的符号与属性集合改比例之后端子显示变小那是绘图比例与符号库的映射问题做过程控制的同事说模型指的是温控系统的 FOPDT 一阶惯性加纯滞后传递函数参数是阶跃响应标定出来的不是从数据里训出来的。再往外延伸Transformer 模型详解、TCN 模型结构、高斯模型、滑动窗口滤波模型、波利亚罐子模型这些模型有的是网络结构定义有的是概率分布假设有的是数学过程。它们的共同点是——组成部分和推导链条是人事先写死的。而 llama 系列、Stable Diffusion、Flux 这一类参数量以十亿计权重是从海量数据里一点点调出来的。这两类东西的调试方法和失效模式完全不同混着聊必然鸡同鸭讲。提示讨论模型学会了什么之前先确认对方说的模型是结构定义的还是参数学习的。前者出错是逻辑错后者出错是数据错排查方向差得很远。1.2 参数型模型的学习边界真正会学会你教它的一切的是第二类参数从数据里学出来的模型。它的学习过程说白了就一句话——沿着损失函数的梯度方向不断调整参数让预测结果和标注越来越接近。这个过程极其老实老实到有点可怕你在标注里写错一个字它记住你在样本里留了一个和标签强相关的无关特征它抓住你把测试样本不小心混进了训练集它背下来。所以模型的能力上限不取决于算法多先进而取决于你给的监督信号里有多少是你真的想让它学的。我见过一个做版面检测的项目模型在验证集上框得极准上线后一遇到扫描件就崩。后来发现训练数据里所有扫描件都是同一台设备扫的模型学到的判别依据是纸面噪点纹理而不是版面结构。它不是没学会它是学会了太多不该学的东西。1.3 一个涨点的假象它学会了模板没学会意图回到开头那个客服意图分类的例子。我让他们做了一件事把验证集里所有由模板生成的样本单独拎出来再人工写 200 条口语化、措辞完全不同的同义问法作为新测试集。结果模型在模板验证集上 94%在人工测试集上 71%。这 23 个点的落差就是学会了模板和学会了意图之间的距离。判断方法其实很朴素换一种从没出现过的表达方式去问同一个问题。如果模型答对了它学到的是语义如果答错了但换个同模板的问法就对了它学到的是表层模式。这个动作花不了两个小时但能省掉一次灰度事故。2. 数据里藏着的答案模型最先学会的往往是你的切分方式2.1 数据泄漏最常见的三种形态数据泄漏是模型学会了你教的一切里最隐蔽的一类问题因为它不会报错只会安静地把指标抬高。我踩过的坑大致归成三类。第一类是样本级泄漏同一个样本或它的近似副本同时出现在训练和验证里。这种情况多发生在爬取数据、多轮增强、多源合并的场景。判断方法是做近似去重用 MinHash 或 SimHash 对文本算指纹用感知哈希对图片算指纹阈值可以先卡在 0.85 左右再人工抽检。第二类是特征级泄漏某个特征在预测时刻根本拿不到但训练时拿到了。最典型的是把后续统计量当特征用比如用整段时间窗口的均值去预测窗口内某一时刻的状态。这种模型离线 AUC 漂亮得离谱上线就直接废掉。第三类是标签级泄漏标注本身包含了答案信息。比如工单标题里写了退款-已处理而你让模型判断是否需要退款处理。模型只要学会看标题后缀就够了业务语义一点没学到。2.2 切分方式决定了你的评测是不是自欺欺人随机切分是最省事也最容易骗自己的做法。当数据里存在分组结构——同一个用户、同一个会话、同一台设备、同一批采集任务——随机切分必然把同组样本打散到两边。正确做法是按组切分把组 ID 作为切分单位保证同一组的样本整体落在训练侧或验证侧。时间序列更要小心。如果业务本身有时序漂移随机切分相当于让模型用未来预测过去指标会明显虚高。这时候应该按时间点切训练集在前验证集在后留一段缓冲期避免边界泄漏。我一般会在切分后跑一个检查脚本统计训练集和验证集在关键维度上的分布差异用 PSI 或 KL 散度量化一下差异超过阈值就回头调切分策略而不是调模型。泄漏形态典型征兆验证手段修复方向样本级重复训练 loss 极低验证 loss 同低但线上崩近似去重 抽检合并或剔除重复样本特征级越界离线指标远超业务常识逐特征核对上线可得性删除越界特征或改为历史窗口统计标签级泄漏模型太聪明解释不通单特征训练看是否已能高分清洗标注剥离答案词分组被打散验证指标波动大且偏乐观按组切分重跑组级切分 分组交叉验证2.3 从 loss 曲线和验证曲线上读征兆很多人看训练日志只看最后一行的数字其实曲线的形态信息量大得多。如果训练 loss 一路平滑下降、验证 loss 很快到达最低点然后持续抬升这是标准的过拟合模型在背训练集如果两者几乎同步下降且验证 loss 低到不合常理那要先怀疑泄漏而不是庆祝。还有一种情况容易被忽略训练 loss 下降得异常慢但验证指标却很好。这通常意味着数据里噪声很大或者标签本身存在大量矛盾标注。同一句话被标成了两个类模型只能学到平均而言哪个类更可能这种情况下先修标注比调参收益大得多。提示训练前花十分钟算一下标签一致性。让两个人独立标 300 条看一致率。一致率低于 85% 的任务模型天花板基本就被标注质量锁死了。3. 微调这一步模型几乎是照单全收3.1 微调到底改的是哪一层预训练模型在预训练阶段学到的是语言的通用规律微调阶段是在这个基础上把参数往你的任务方向推一把。全参微调会把所有权重都动一遍LoRA 这类低秩适配只训练少量新增的旁路矩阵主干权重冻住。两者的差别不只是显存占用更是模型被你的数据改造得有多深。这一点直接决定了它对你数据里噪声的敏感度。全参微调在小数据集上特别容易把噪声当规律学走因为它有足够的自由度去拟合每一条样本。LoRA 因为可训练参数少天然带一点正则化效果但代价是任务差异大时学不透。我一般这样选数据量在万条以上、任务和预训练分布差异大用全参微调或者较高 rank 的 LoRA数据量在千条级别优先 LoRA先把 rank 压在 8 到 16 之间试。3.2 LoRA 的 rank、alpha、target modules 怎么定这三个参数是 LoRA 微调里最常被调错的。rank 决定低秩矩阵的秩也就是模型有多少余地去改alpha 是缩放系数实际生效的是 alpha 除以 rank 这个比例target modules 决定给哪些层挂旁路。我的经验口径是这样的rank 从 8 起步任务复杂比如需要用模型做结构化抽取、多轮推理就往上加到 16 或 32alpha 通常设成 rank 的两倍让缩放比稳定在 2 左右target modules 至少覆盖注意力里的 q_proj 和 v_proj如果任务涉及输出格式的强约束把 k_proj、o_proj 以及 MLP 层的 gate、up、down 也加进去效果会比只挂 qv 明显好代价是显存和训练时间上去了。还有一个经常被忽略的点学习率。LoRA 的学习率一般要比全参微调高一个量级常见区间在 1e-4 到 3e-4。用全参微调的学习率去跑 LoRA你会发现 loss 几乎不动然后误以为LoRA 不适合这个任务其实是没训起来。3.3 小样本下的灾难性遗忘小样本微调最典型的副作用是灾难性遗忘模型在你的任务上变强了但通用能力掉得厉害甚至会开始用你的任务格式去回答所有问题。表现是——原本能正常对话的模型微调之后问它任何问题都往你的标签上靠。缓解手段有几个我按见效快慢排一下。最直接的是混入通用数据在微调集里掺 10% 到 20% 的通用指令数据让模型知道不是所有输入都是我这个任务。其次是降低训练轮数小数据集跑 1 到 3 个 epoch 通常就够了跑到 5 个 epoch 以上基本就是在背样本。再就是用较低的学习率加 warmup让参数变化平缓一点。这里我想强调一个实操细节每个 epoch 存一次 checkpoint然后在通用能力测试集和任务测试集上各跑一遍。很多时候最优解在第二个 epoch而不是最后一个。只看最后一个 checkpoint 是很多人翻车的起点。4. 蒸馏像复印教师的笔误会被一起复刻4.1 软标签里装的不只是知识知识蒸馏的核心思路是让学生模型去拟合教师模型的输出分布也就是软标签而不是只有硬标签。软标签里携带了类别之间的相对关系比如教师认为这张图是猫的概率 0.7、是狗的 0.2、是狐狸的 0.1这个 0.2 和 0.1 就是额外的信息量。但这里有个陷阱教师模型的错误同样以概率形式存在。如果教师在某个类别上有系统性偏好比如对少数类总是给偏低的概率学生学到的就是带着这个偏见的分布。更糟的是教师的偏见往往在硬标签上被掩盖了——因为只看 top-1 的话教师还是答对的可软标签里的错误结构已经被完整传递下去了。4.2 温度和权重学生为什么会比老师更自信温度 T 是软标签的平滑系数T 越大分布越平学生能从中学到更多类别间的相对关系T 越小越接近硬标签。常规做法是 T 取 2 到 4 之间同时把蒸馏损失和硬标签交叉熵损失加权求和权重一般在 0.5 到 0.9 之间。我遇到过几次学生比老师更自信的现象学生模型在错误样本上给出的置信度高达 0.95 以上而教师在同一批样本上只有 0.6 出头。原因通常是硬标签损失的权重给太高学生被硬标签拉成了非黑即白的判别器把教师原本保留的那点不确定性抹掉了。这种模型在线上特别危险因为它不会给你任何我不确定的信号告警阈值做成什么样都会被绕过。4.3 蒸馏必须做的对照实验蒸馏做完只比一个总准确率是不够的我会固定跑三组对照。教师 vs 学生在同一批对抗样本上的表现找教师答错的样本看学生是否错得一致。错得越一致说明继承的偏见越多。置信度分布对比统计两个模型在正确样本和错误样本上的置信度均值正常情况学生的置信度应该略低于或接近教师而不是整体更高。教师没见过的领域数据在教师本身表现一般的领域上测学生看学生是否退化得更严重。这三组跑下来基本能判断出蒸馏是传递了规律还是复制了错误。5. 把模型压小之后它记住的东西还在不在5.1 量化与剪枝对记忆的破坏方式不同模型压缩经常被当成纯工程优化好像只是把模型变小、跑得更快内容不变。实际上不同压缩方式破坏的是不同的东西。量化是把权重从高精度压到低精度比如从 FP16 压到 INT8 或 INT4。它的影响更像给每个参数加了一点均匀噪声对绝大部分泛化型能力影响不大但那些依赖极少数关键参数才能触发的行为——比如严格的输出格式约束、特定的终止符生成——会最先崩掉。所以我做量化之后一定会单独测格式合规率而不只是测准确率。剪枝是直接删掉一部分权重或结构破坏性更直接。它删掉的往往是不常用的通路而长尾类别的判别恰恰依赖这些不常用通路。表现为整体指标掉得不多但少数类召回率断崖式下降。这时候要按类别看指标而不是只看宏平均。5.2 端侧部署时的实测口径要在算力受限的设备上跑模型通常会走导出加转换的路线比如先导出成通用中间格式再转成目标平台的推理格式。这一步最容易被忽略的是算子对齐训练框架里的某个操作在推理侧可能被拆成两个近似算子数值误差累积之后输出分布就偏了。我的惯例是准备一套 200 条左右的端到端对比样本在同一批输入上分别跑原始模型和转换后的模型逐条比对输出。文本任务比 top-1 是否一致和概率分布的差异幅度视觉任务比框位置偏差和类别置信度差异。如果一致率低于 98%先别急着上端侧回头查算子实现。还有一个容易被忽视的细节目标检测这类任务里前后处理的参数比如锚框尺寸、缩放比例、归一化均值方差如果和训练时不一致模型本身没错但结果会整体偏移。我见过一个案例模型转换没问题就是归一化均值少了个小数点导致线上检测结果系统性偏移查了两天才定位到。5.3 模型融合与多模型协作把错误分散掉当单个模型的错误已经触到天花板一个务实的做法是模型融合。最简单的是概率平均把多个模型的输出分布加权求和权重可以用各自在验证集上的表现来定。它对随机性错误很有效因为不同模型的随机错误方向不一致平均之后会被抵消但对系统性错误基本无效如果几个模型都是在同一批脏数据上训出来的它们会一起错。所以融合模型的选择原则是架构不同、数据源不同、训练时的随机种子不同。三个条件里至少满足两个融合才有意义。如果只是同一个模型跑三次不同种子收益通常只有零点几个点。多模型协作是另一条路让一个模型负责判断这个问题该交给谁再由专门的模型处理。这条路的好处是每个子模型只需要在自己擅长的领域做强坏处是路由模型本身的错误会直接变成系统错误而且错误更难归因。我的建议是路由模型一定要做得保守宁可多交给通用模型也不要错交给专用模型。6. 上手排查怎么判断模型是学会了还是背会了6.1 反事实样本与扰动测试判断一个模型学到的是规律还是捷径最有效的工具是反事实样本保持语义不变只改变表层形式。文本任务里可以做同义替换、语序调整、口语化改写视觉任务里可以做亮度调整、局部遮挡、背景替换。具体做法是对同一批样本生成三到五组扰动版本看模型预测的一致性。如果语义没变但预测变了说明模型依赖了不该依赖的特征。扰动前后的准确率落差如果超过 10 个点这个模型基本不能上生产。这里有个技巧扰动要有针对性。如果怀疑模型在看背景那就只换背景如果怀疑模型在看某个关键词那就只替换那个词。全面扰动虽然简单但出了问题也不知道该修哪。6.2 校准与置信度检查一个模型学会了的标志之一是它的置信度和实际正确率大致匹配。如果模型说 0.9 置信度的样本里有 40% 是错的那它就是在瞎自信这种模型没法配阈值也没法做人工复核分流。检查方法是画可靠性曲线把预测概率分箱统计每个箱里的实际准确率。理想情况是两者接近对角线。偏差大的话可以用温度缩放做后处理校准这是成本最低的一种修正手段只需要在验证集上拟合一个温度参数不用重训。提示业务侧最关心的往往不是最高准确率而是高置信区间能不能做到 95% 以上精确率。所以校准这件事优先级经常比再涨一个点准确率更高。6.3 上线前的灰度、埋点与回归集维护我在实际项目里的做法是不管离线指标多漂亮上线一律走灰度。灰度阶段要盯三件事整体指标的线上表现、模型置信度的分布变化、以及被模型判为高置信但人工复核后判错的样本。第三件事最关键我一般会让团队每周抽 200 条线上高置信样本做人工复核把错的那部分收进回归集。回归集不是越攒越多就好要定期做去重和采样保持每个类别、每种错误类型都有代表样本。一个维护得当的回归集能在模型迭代时提前拦住大部分回归问题。另外一个常被忽略的点是线上输入分布会漂移。用户的表达方式、商品的品类、季节性的问法都在变。所以除了模型指标还要监控输入侧的统计量比如平均长度、词汇分布、类别触发频次。输入侧的异常往往比输出侧的指标下降早出现几天能给你留出反应时间。最后再分享一个我在实际操作中的体会。每次模型表现异常我的第一反应不是去看模型而是去看数据。过去几年里我处理过的模型问题里大概七成根因在数据——切分错了、标注错了、特征越界了、增强模板重复了。模型极少主动骗人它只是太老实地把你给它的东西全学会了。真正需要反复推敲的从来是我到底教了它什么。
返回列表