如果你负责把一个第三方模型接入自家系统,最危险的时刻不是它跑不起来,而是它跑得一切正常——正常到让你差点把它推上线。上个月我在做 WhatsApp 优先的深度伪造与恶意软件验证平台时,就遇到了这样一个模型:Spectra-AASIST3,一个 Apache-2.0 协议的音频深度伪造检测器。它加载干净,1022 个权重键全部匹配,3.189 亿参数无一处报错;前向传播响应灵敏,对静音、真实人声、包络噪声、纯音分别给出 1.63、1.76、1.33、2.8~4.0 的分数。它显然不是坏掉的,不是退化的,不是输出恒定的死模型。它活着,而且反应敏捷。于是所有集成测试都告诉我:这个组件没问题。

Priyansh Kansara
Priyansh Kansara

但集成测试只回答一个狭窄的问题:组件能不能跑起来?能不能加载?能不能对输入产生输出?它不回答那个真正关键的问题:能不能区分?在我关心的数据上,它能不能分清真实声音和合成声音?这两个是不同的命题。把它们混为一谈,就是你把一个通过所有单元测试、却在每个用户面前翻车的模型送上线的方式。

为了避免事后给自己找理由,我在跑评估之前,白纸黑字写下了验收标准:在留出集上 AUC ≥ 0.85,两个类别的后验分位数不重叠,全局后验标准差高于 0.01。三个条件必须同时满足。提前定下标准,是这件事能干净收场的唯一原因。一旦你面前出现一个数字——不管什么数字——你就会忍不住反向推理。0.54 可以变成“只是切片太小”“标准定得太严”“厂商的数据集本来就不一样”,这些说法也许都是真的,但如果你在测量之前就承诺了那个标准,它们就都不重要。标准不是结论,是决策规则。你要在还没被结果诱惑的时候定下它,然后接受它。

pic
pic

我用的评估集是 ASVspoof 2019 LA 验证集中的 240 条片段,120 条真实、120 条伪造,从 Bisher 验证 parquet 里抽出来的。结果:AUC 0.54。后验分布更难看:类别 0 和类别 1 的四分位距都压在同一条带子里(约 0.044~0.049),两条分布不是重叠,而是几乎完全重合。全局后验标准差 0.0046,比我设的 0.01 阈值低了一个数量级。模型自信地给出了输出,只是对真实和伪造音频给不出有差异的输出。

厂商公布在 ASVspoof 2019 LA 上的 AUC 是 0.9967,我实测是 0.54。这差距大到我不敢假装自己知道原因。厂商是在完整测试集上算的,共 71,237 个 trial;我是在校验集 240 条切片上算的。评估集不同,规模差了三个数量级。有可能模型在完整测试分布上确实远好于这个切片;也有可能是这个切片自身的来源、标签平衡或声学特征比测试集更难。我不知道哪个是真,也不打算装作知道。我能确认的是,这个矛盾还没解开。要解开就得在官方 ASVspoof 2019 LA 评估音频(2.7GB,我还没处理)上重跑评估。在那之前,0.54 是我唯一能辩护的数据,也是我用来做决策的数字。

所以我没有把这个模型接进服务链路。音频保持仅用于校准(calibration-only)。厂商代码我仍然留在仓库里,以便将来拿到官方评估证据能迅速重新验证,但基座编码器的权重文件不进 git,模型不参与任何面向用户的决策。这个项目并不需要一个不工作的音频通道。它已经有一个融合引擎,能融合视频、图片、URL、政府文档四个渠道的校准信号。加一个 0.54 的组件不会让系统变好,只会更复杂、更不可信,因为每个下游消费者都得为一个不带任何信息的信号买单。

DEV Community
DEV Community

这不是我第一次做这种决定。早在这个项目里,我训练过一个逻辑回归融合栈,跑在基础音频检测器上的 OOF(out-of-fold,折外预测,即用训练时没见过的样本预测出的结果)AUC 是 0.512,而启发式基线是 0.502;梯度提升的变体在 n=84 上只有 0.499,接近随机。这两个都没上线。让我不舒服的是那个单次切分训练报告的数字:0.634。这个数字是真实的——它确实是某次训练跑出来的真实输出——但它也是好看的,因为那一次切分恰好对模型有利。折外数字 0.512 才是诚实的那个,也是更差的那个。我汇报了更差的数字。

这个纪律说起来简单,做起来难。当你手上有两个数字,其中一个更好看,更好看的那个就会拼命想钻进 commit message、README、作品集;更差的那个才反映模型在没见过的数据上的真实表现。你要汇报更差的数字,并解释为什么它更差,然后继续。

集成测试证明组件能跑,不证明组件能区分。加载 checkpoint、匹配权重键、确认前向传播对输入有响应——这些都是必要条件,也很容易满足。每个厂商 Demo 和每个快速上手 notebook 都能满足这些条件,因为它们本来就只展示容易展示的东西。区分能力是独立的属性,必须在代表你的真实问题的数据上,用你看到结果之前就定下的标准来衡量。如果你不提前定标准,你总会为任何出现的数字找理由:切片太难、厂商的数据集不同、0.54 已经够接近了。你会错,而且不会知道自己错,因为你已经在事后说服了自己。

我宁愿一个系统少几个渠道、但对现有渠道更有信心,也不要一个音频检测器通过所有集成测试却分不清真实和伪造。这个模型没有坏,它只是被我在测量之前定下的标准拒收了。这就是全部的故事,也是最有意思的部分。

对做 AI 工程的人来说,这里面有直接能用的教训:第一,任何第三方模型接入前,先写死验收指标,别等评估完再说;第二,优先信任在留出集或折外预测上的数字,而不是单次切分的好看数字;第三,区分“组件能运行”和“组件能判别”这两个完全不同的性质。你要是把这两件事混在一起,迟早会推一个 0.54 的模型上线,然后在真实用户面前才发现它什么都没学会。

阅读原文 → 返回 AI 技术文档

内容与图片版权归原作者所有 · 原文: https://dev.to/dawnofgenx/i-rejected-a-model-that-passed-everyone-elses-benchmark-33gm