一篇读懂评测污染:你的 Benchmark 分数可能是个假象

一个刺眼的实验:把 GSM8K 重写一遍会怎样

LLM 评测污染的检测与应对

GSM1k 的构造逻辑

要检验一个模型在 GSM8K 上的高分是「会做题」还是「背过题」,最直接的办法是出一套分布相同但保证全新的题。Scale AI 团队 2024 年的 GSM1k 论文(Zhang 等人,arXiv 2404.04475)就是这么做的:组织标注员模仿 GSM8K 的每道题,从题面结构、数字量级、解题步骤数到答案形式逐一匹配,手工写出 1250 道全新小学数学题,再经独立审核确保与原题无文本与逻辑复用,并用小模型验证难度分布一致。这样得到的 GSM1k 与 GSM8k 在统计性质上是同一分布的两个独立采样——如果模型真正掌握了这个分布的能力,两边分数应当接近。

实验结果值得每个做评测决策的人记住。对全家桶模型做对比,多数前沿模型(GPT-4o、Claude、Gemini 系)在 GSM1k 相对 GSM8k 的掉点很小(一两个百分点以内,与抽样噪声同量级);但部分开源模型家族出现了系统性大掉点——某些 Mistral 与 Phi 早期版本的掉点超过 8 个百分点,个别配置达到 13 个点。更耐人寻味的相关性证据:掉点幅度与模型在 GSM8k 上的「分数增速」正相关,而不是与模型大小正相关。这个模式指向的解释只有一个:这些模型的训练数据里混入了 GSM8k 的题面与答案,高分是记忆的产物而非推理能力。

为什么这不是孤例

同样的故事在别的基准上反复上演。一个经常被引用的自然实验是 AIME(美国数学邀请赛):有研究(如 GPT-4 系统卡附带的讨论与后续多项分析)观察到同一批模型在 AIME 2024 之前的题目上分数逐年走高,而 2024 年当年及之后的新题分数断崖式低于 2023 年及更早的同难度题——如果模型真有那么强的数学能力,年份不该是分数的预测变量。代码基准同样中招:HumanEval 及其变体的题面与答案在 GitHub 与各类博客上广泛流传多年。结论很硬:静态公开基准的分数天花板会被污染持续侵蚀,评测者的默认假设应当是「公开基准的分数存在高估」,除非模型方给出了去污染证据。

污染的三条进入路径

网络抓取:原题就在语料里

第一条路径最直白:评测集的题面本来就在互联网上。GSM8k 发布于 2021 年 10 月,之后 OpenAI 的论文把它传开,全世界的题解博客、GitHub 仓库(含完整 answer key)、Kaggle notebook 都收录了原题;这些页面又会被后续的语料抓取收录进 Common Crawl,再进入任何一个 2022 年之后启动的预训练语料。一条具体的时间线就能说明问题:凡是「基准发布时间早于训练数据截止时间」的组合,污染风险都是结构性的。GPT-3 时代的做法是在训练后做 13-gram 重叠检查(Brown 等人,2020),发现与评测集重叠的样本占比极小就放心——这个检查的盲区后面细讲。

第二条路径更隐蔽也更难治理:合成数据的自我污染。当前数据工程大量使用 LLM 生成训练数据,而生成模型自己就是在「含基准题的互联网」上训出来的。让 GPT-4 生成一万道数学题,产物里会以一定比例出现 GSM8k 题目的改写版——数字换了、句式换了、但解题结构一模一样。这些「近亲题」混入微调集,模型对原题的泛化就被记忆悄悄替换了。第三条路径是人工环节:标注员、审题人、开源贡献者都见过原题,人工仿写如果只是换个皮(GSM1k 之所以专门做独立审核与难度校准,就是为了防这条)。

检测的第一层:n-gram 与它的盲区

n-gram 重叠是工业界的标配去污染手段:把每道评测题拆成 n-gram(常见取 8 到 13),在训练语料里做倒排索引查找,命中即把含该 n-gram 的文档整条剔除。Llama 3 的技术报告描述了其去污染管线对知识与推理基准用类似粒度的重叠检查。但这个方法的盲区是结构性的:改写题在每个 n-gram 窗口上都不同。把「小明有 3 个苹果」改成「小红买了 3 只苹果」,13-gram 检查颗粒无收,而两道题对模型是同一道题。GSM1k 论文专门讨论了这一点:仅靠表层重叠检测无法发现语义级污染。工程上的实用妥协是双层过滤——表层 n-gram 负责便宜的粗筛,语义层用 embedding 相似度(题面 embedding 与语料段落 embedding 的近邻检索)补漏,后者按 0.8 左右的阈值召回候选再人工复核。

# 表层去污染的最小实现:13-gram 倒排索引
from collections import defaultdict

def ngrams(text, n=13):
    words = text.lower().split()
    return {" ".join(words[i:i+n]) for i in range(len(words)-n+1)}

index = defaultdict(list)
for doc_id, doc in enumerate(corpus):
    for g in ngrams(doc):
        index[g].append(doc_id)

def contaminated_docs(eval_question):
    hits = set()
    for g in ngrams(eval_question):
        hits.update(index.get(g, []))
    return sorted(hits)   # 命中文档整条剔除或人工复核

检测的第二层:Canary 与 Min-K%

对付「语料里有没有这道题」还有两个互补的武器。Canary 字符串(BIG-bench 引入,GUID 形式嵌入数据集文档):基准发布时在数据文件里埋入唯一随机串,任何直接吞下该数据集的语料都会带上它——检测时在模型 tokenizer 层面查 canary 是否被记进词表、或用模型续写 canary 前缀看能否补全,一击命中「整个数据集文件被摄入」的场景。Min-K% Prob(Shi 等人,2024,arXiv 2310.16789)从模型侧检测:把候选文本喂给模型,取每个 token 的条件概率,看概率最低的 k% token 的平均对数概率。直觉是:模型见过的文本,那些「不可预测」的实词也会呈现异常高的似然(模型对全文的「惊讶度」分布平坦),而没见过的文本惊讶度方差大。该方法在预训练数据检测任务上拿到了当时最好的 AUC,适合做「这段评测题面是否在模型记忆里」的逐例判定。三个方法合起来构成完整的检测矩阵:n-gram 抓表层、canary 抓整文件、Min-K% 抓语义记忆。

flowchart TD
    A[评测集与模型候选] --> B{基准发布早于数据截止}
    B -- 否 --> Z[低风险 定期复检]
    B -- 是 --> C[13-gram 表层重叠筛查]
    C --> D{命中率高}
    D -- 是 --> E[语料级剔除 对应训练批次]
    D -- 否 --> F[题面 embedding 近邻检索]
    F --> G{语义近亲命中}
    G -- 是 --> H[人工复核确认改写污染]
    G -- 否 --> I[Min-K% 逐例检测记忆]
    I --> J{记忆信号阳性}
    J -- 是 --> K[标注该基准分数不可信]
    J -- 否 --> Z

扰动测试:行为学判别「能力还是记忆」

检测语料之外,还有一条从模型行为侧入手的判别路线:扰动测试。逻辑很直接——真正掌握解题能力的模型对题面的表层变化应当鲁棒:把 GSM8k 题里的名字从「小明」换成「小李」、数字从 3 换成 7、单位从苹果换成橘子,正确率不应显著变化;而背题的模型在扰动版上的分数会明显低于原版,因为扰动恰好破坏了它与记忆中题面的精确匹配。GSM1k 本质上就是一次大规模、高成本的扰动测试。工程上有更便宜的近似:对每道评测题自动生成 3 到 5 个保结构变体(程序化替换实体与数字、重算答案),模型在「原题减变体」上的分数差就是记忆嫌疑度,超过阈值的基准要降权处理。这个方法的局限也要说清楚:它检测的是「精确记忆」,对「题解文章被大量阅读后形成的模式记忆」灵敏度有限——后者正是合成数据近亲污染的形态,所以扰动测试与语料检测互为补充,谁也替代不了谁。

合成数据的二次污染:一个会自我强化的循环

污染问题在合成数据时代出现了一个更隐蔽的放大机制,值得单独警觉。循环是这样的:基准题泄进语料 → 模型 A 在基准上「高分」→ A 被用于合成训练数据 → 合成数据里带有基准题的解题模式(甚至原题改写)→ 模型 B 在 A 合成的数据上训练 → B 在基准上继续「高分」。两代之后,污染不再是「语料里有没有原题」的二值问题,而是弥散在整个合成数据分布里的模式遗传——n-gram 检测、embedding 检测全部失效,因为每一代改写都在远离原题表层。阻断这个循环只有两个位置:在合成数据的源头审计(对每批合成数据与公开基准做语义相似度抽样审计,而不是只审原始语料),以及在评测端保持持有集的绝对清洁(持有集的题目从构造到评测全链路不经过任何 LLM——包括「用 LLM 检查这道题好不好」这种看似无害的环节,因为那也是一次数据暴露)。

评测方的对策:动态与私有

军备竞赛的正确姿势

检测是被动的,主动策略是让基准本身难被污染。三条路线。第一,动态化:LiveBench(2024)按月更新题目,题面来自当月新发表的论文、新闻与代码库;LiveCodeBench 用发布时间分桶统计题目,专门报告「模型数据截止之后的新题」分数,让污染一目了然。第二,私有化:核心评测不放公开网络,只通过 API 交互(各类私榜的本质),代价是无法社区复核、且有隔墙有耳的泄露风险。第三,持有集(held-out)策略:基准方发布 90% 题目、私留 10% 定期重评——这套机制的博弈论味道很浓:训练方若贪题面,会同时污染可见集,而持有集分数不掉的模型才可信。

模型使用方的三条防线

如果你是选型的工程师而非训练方,防线有三。第一,看分数构成不看单点:同一模型在多个独立基准上的分数矩阵比任何单榜都有信息量;单一基准的异常高分(比如数学暴涨但代码不动)本身就是污染红旗。第二,自建小持有集:从自己业务里手工构造一两百道题、永不上传网络,每季度人工维护——这个集合的分数比所有公开基准加起来更能预测模型在你的任务上的真实表现,成本只有一两个标注员周。第三,读模型卡的去污染声明:认真报告「训练数据截止时间、对常用基准做了何种重叠检测、检测结果」的模型方,可信度系统性更高;对这个问题避而不谈的技术报告,默认打折。

一张污染风险检查表

把全文收敛成可执行的清单:评测选型时检查「基准发布时间 vs 模型训练数据截止时间」,前者早于后者就要求去污染证据;训练方在数据管线上配 n-gram 粗筛加 embedding 语义细筛双层检查,合成数据要额外做与公开基准的相似度审计;模型侧用 Min-K% 对高分基准做逐例记忆检测;分数解读时永远看多基准矩阵,单点异动先查污染再庆祝;重要决策依赖自建持有集而不是公开榜单;长期项目选动态基准或带持有集机制的基准。最后一句实话:污染不可能被归零——公开的互联网基准终将被侵蚀,评测体系的可持续性不取决于某次完美清洗,而取决于「持续出题的机制」。

小结

评测污染是「分数通胀」的机器:GSM1k 的实验给出了最干净的证据——分布相同的 1250 道新题让部分开源模型掉点超 8 到 13 个百分点,而前沿模型只掉噪声级别的一两点,掉点与「训练语料接触过原题」高度相关;AIME 新题分数的断崖是同一个现象的免费复现。污染的三条路径(原题入语料、合成数据近亲、人工环节泄露)里前两条是结构性的,n-gram 检测抓不住语义改写,需要 embedding 近邻与 Min-K% 记忆检测补位,canary 则守住「整文件被摄入」的场景。对策的天平正在从「事后清洗」滑向「动态与持有」:LiveBench 式持续出题、私有评测与自建持有集,才是与「背题能力」的军备竞赛里可持续的位置。记住这个判断法则:一个模型在你无法验证污染状态的基准上的分数,只是它「见过的题」的函数;它没见过的题的分数,才是它的能力。

← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?