美食城每年举办一届“国厨杯”厨艺大赛,评委手里有一份绝密的评分菜单。参赛的 AI 厨师“小灶”靠吞食海量网络菜谱来学习做菜。麻烦的是,网上流传的菜谱库里居然混进了评委菜单的翻拍照——被爬虫当成普通帖子抓了进来。小灶把菜单背得滚瓜烂熟,比赛时端出的菜确实惊艳全场,但那不是真本事,是背答案。在 AI 界,这叫作“评测数据污染”:训练数据里混入了评测集的题目,导致模型分数虚高、能力失真。而去重策略(Dedup),就是大赛组委会赛前派出的品控小组:把菜谱库里所有“长得像评委菜单”的菜全部挑出去,逼着小灶真正学会做菜的原理。这篇文章就是品控小组的完整工作手册——从污染成因与危害讲起,再看相似度怎么度量、阈值怎么定、跨数据集去重流程怎么跑,最后聊聊去重对训练效果的双重影响,以及如何用制度守护评测的长期公平。
掌握去重策略,是 AI 评测工程师守住“分数真实性”的底线技能——既能识破榜单虚高,也能为模型训练提供更干净的数据。
可视化演示
三步展示数据污染去重Dedup:精确匹配/n-gram模糊/语义去重算法演进、归一化→精确→模糊→语义→报告的流水线、以及精度与召回权衡的阈值设定。
本节配有交互动效(进入视口后自动加载,约 3KB)。
匹配算法演进 精确匹配:归一化逐字符比对 n-gram: 模糊近似匹配 语义:embedding余弦相似度 精确→模糊→语义 捕获不同层级的重复。
污染成因与危害
比赛前三个月,组委会抽查小灶的菜谱库,吓了一跳:角落里躺着几十本“评委内部资料”,页脚还印着“国厨杯·请勿外传”。原来,这些资料被人拍照发到美食论坛,又被爬虫抓进了公开菜谱库。小灶照单全收,背得滚瓜烂熟。问题不在小灶贪心,而在于“食材入库”时没人把关。
现实中的大模型同样如此。评测集为了公平往往公开题目(如 MMLU、HumanEval、GSM8K),这些题面广泛流传于 GitHub、论文、问答社区。训练数据的爬虫并不认识“这是考试题”,于是它们混入语料库,形成“数据泄漏”——就像评委菜单的翻拍照混进菜谱论坛。模型在预训练时把这些题目背下来,测试时自然“手到擒来”。
这种污染的直接后果是“作弊式高分”:模型并非掌握了推理能力,而是复现了记忆。更隐蔽的是,污染样本占比越高、与答案绑定越紧(如带着完整解题过程的数学题),虚高就越严重。要量化这种伤害,我们可以计算污染率:训练集中与评测集高度相似的样本占总样本的比例,比例越高,比赛成绩越不可信。
明白了污染的来龙去脉,品控小组才能下定决心:不仅要清理,还要先立规矩——接下来就是清库行动的核心逻辑:去重原理。
- 分子 N_dup训练集中与评测集相似度超过阈值的样本条数,对应“菜谱库里混进评委菜单的菜量”。
- 分母 N_train训练数据总共包含的样本条数,作为衡量污染的基准盘。
- 比值与百分号两者相除再乘以 100%,把污染程度转化成直观的百分比。
去重原理与定义
品控小组开会定方案:不能把整个菜谱库倒掉,只消灭“与评委菜单相似”的菜。他们搬出评委菜单,逐道菜比对:凡是食材顺序、烹饪步骤和评委菜单重合度超过八成的,一律下架。这套“以评委菜单为参照、按相似度清理”的思路,就是去重策略的雏形。
技术上讲,去重(Dedup)是数据预处理阶段的一道工序:以评测集为参照,逐条计算训练样本与任一评测样本的相似度,超过阈值则剔除。去重分两个层次:精确去重针对完全相同的样本(如哈希碰撞比对),模糊去重针对改写、拼接、翻译后的高相似样本——后者才是污染的主力,因为“改头换面的菜单”最难抓。
判定规则可以写成一条清晰的分支函数:对每个训练样本 x,计算它与评测集 E 的最大相似度 sim(x,E),若不低于阈值 τ 就标记为重复并剔除,否则保留。阈值 τ 就是品控的标准线:“像到什么程度算偷题”。
有了判定规则,品控小组还需要一把“尺子”——怎么量化“像不像”?下一节,我们走进后厨,看他们如何把菜切成小片来数重合。
- x(待检样本)训练数据中的一条样本,相当于仓库里的一袋待查食材。
- sim(x,E)(最大相似度)该样本与评测集任意一条样本的最高相似度,衡量“它与评委菜单有多像”。
- τ(阈值)判定是否重复的分界线,由品控小组按风险权衡设定。
- D(x)(判定输出)相似度不低于阈值时判为重复并剔除,否则保留。
相似度度量
品控员老周有个土办法:不看整道菜,先切成小片。番茄炒蛋切成“番茄”“炒”“蛋”的碎片,谁和评委菜单对上的碎片多,谁就可疑。碎片越小越碎,比对越灵活——改几个字、换个说法,也逃不过碎片的排查。老周的经验,正是 n-gram 思路的雏形。
在计算机里,我们把文本切成连续 n 个字符(或词)的片段集合,再比较两个集合的重叠程度。最常用的指标是 Jaccard 相似度:两段文本共有的片段数除以它们全部片段数。重合片段越多,比值越接近 1,文本就越像。n 较小时匹配宽松、召回高;n 较大时匹配严格、误报低,但漏网也随之上升。
直接两两比对全部文本代价极高——百亿级语料乘以万级评测题,计算量不可承受。工业界常用 MinHash 做“指纹化”估计:对每个大集合算出几十个最小哈希值作为签名,签名重合率近似 Jaccard;或者用向量化模型(如 embedding 余弦相似度)在语义层面捕捉“换说法但意思一样”的改写。无论哪种尺子,度量的都是“像不像”。
有了尺子,下一步是定标尺上的刻度——阈值。松紧之间,藏着去重成败的关键。
- S_x 与 S_e(片段集合)把训练样本和评测样本分别切成 n-gram 片段,得到两个集合。
- 交集(共同片段数)两个集合共有的片段数量,是“撞菜”的直接证据。
- 并集(全部片段数)两边所有片段合并去重后的总数,用作归一化分母。
- 比值(Jaccard 系数)交集除以并集,结果介于 0 与 1 之间,越接近 1 越相似。
阈值设定策略
老周画了一条线:相似度超过多少算“偷题”?画得太高,改头换面的题溜进菜谱库,污染照旧;画得太低,正常菜谱被误判下架,小灶的“食粮”白白浪费。这条线的位置,直接决定清库行动的成败。
这就是阈值的双刃剑效应。阈值 τ 与两类错误强相关:τ 越高,漏网率上升——真正重复的样本被放过;τ 越低,误伤率上升——正常样本被误删。两者不可兼得,只能按代价权衡。因为漏网的污染会直接虚高评测分、误导后续决策,通常对漏网施加更高的惩罚权重。
实操上,阈值依赖相似度指标:n-gram Jaccard 常用 0.5 到 0.8,8 到 13-gram 完全命中即可判重;embedding 余弦相似度常取 0.75 到 0.85。更严谨的团队会先抽样标注一批“肯定是污染”和“肯定干净”的样本,画出相似度分布曲线,在两类样本的交叠处取阈值,使总风险最小。
刻度定好,清库行动正式启动。这不再是一道菜一道菜地比,而是一场覆盖整座仓库的大扫除——跨数据集去重流程。
- P(漏网)阈值偏高时,真正重复的样本没被识别出来的概率,对应“改头换面的题混了过去”。
- P(误伤)阈值偏低时,正常样本被误删的概率,对应“普通菜谱被冤枉下架”。
- α 与 β(代价权重)分别为漏网和误伤赋予的惩罚权重,漏网会直接虚高分数,通常 α 更大。
- 总风险函数加权求和得到总风险,选择使 Risk(τ) 最小的阈值即为最优策略。
跨集去重流程
大赛前夜,品控小组按标准流程作业:第一步,把历年评委菜单全部收齐,不仅今年,去年、前年以及坊间流传的“疑似菜单”统统登记造册;第二步,给每道菜做好指纹标签;第三步,开着传送带,让整座仓库的菜谱流水般经过检测仪。三步缺一不可。
技术流程对应如下:先收集评测集(题目与参考答案),把评测文本分块、建索引或布隆过滤器、生成 MinHash 签名;然后流式扫描训练语料,逐条或分批计算每条样本与评测集的最高重合度,超阈值即剔除;剔除过程要与新数据写入、数据混洗配合,避免破坏训练分布。每一步都有明确的输入输出,像一条自动化生产线。
跨数据集去重的“跨”还体现在范围上:不只比对当前排行榜,还要纳入历史评测集、竞品公共基准,甚至待发布的私有集(内部隔离后参与比对)。流程末端必须有抽检验证:人工检查被剔除样本确实是污染、保留样本确实干净,防止索引漏配或误伤。而抽检的依据,正是每条样本与评测集的重合片段计数。
大扫除结束,库房清爽了,小灶的食谱变“薄”了。有人担心:学的东西少了,它会不会变笨?这就要看清去重的双重影响。
- G(x) 与 G(e)(片段集合)训练样本与评测样本各自的 n-gram 集合,是比对的基本单元。
- 指示函数 1[·]当括号内条件成立时取值 1,否则为 0,用于逐片段统计“是否重合”。
- 累加求和对样本 x 的每个片段逐一判断并求和,得到与评测样本重合的片段总数。
- 重合计数O(x,e) 越大代表两段文本越像,是后续阈值裁决的直接输入。
训练效果影响
比赛当天,小灶面对“从未见过的新菜式”,居然做得行云流水。评委们恍然大悟:以前它只是背熟了评委菜单;现在菜单没了,它不得不理解火候、调味、食材搭配的底层规律,反而学会了举一反三。删掉“参考答案”非但没让它变笨,还逼出了真本事。
这正是去重双重影响中的正面一半。训练集中的重复评测样本本质上是“记忆包袱”:模型用参数去存储题目答案,而不是学习可泛化的规律。去除它们,模型被迫把容量花在真正的模式学习上,在分布外数据上的泛化能力与鲁棒性通常更好。换句话说,去重减少了死记硬背,提升了泛化能力。
但负面一半也真实存在:去重会折损数据量,尤其当评测集很大、与训练分布高度重叠时。对数据饥渴的大模型而言,数据量下降可能带来轻微的能力损失。因此业界默认原则是:以“评测公平”为硬约束,把去重造成的训练损失控制到最小。观测得分可以拆成真实分与泄漏虚高分之和,去重的目标就是剥离虚高,让分数回归真实。
小灶夺冠,但台下更重要的是一套长期制度——比赛公平不能只靠一次清库。组委会着手建立持续的公平保障机制。
- S_test(观测得分)模型在评测集上实测得到的分数,是“看起来的实力”。
- S_real(真实能力分)模型真正掌握规律后应得的分数,是“实际厨艺”。
- S_leak(泄漏虚高分)因背过重复样本而多拿的分,去重后被剥离。
- 叠加关系观测得分等于真实分加上虚高分,去重的目标就是让 S_leak 归零。
评测公平保障
组委会宣布三项新规:每届比赛前公开清库报告(去重策略、阈值、剔除数量);增设“私房密室题库”(保密 holdout 集),赛前不接入任何爬虫可见的网络;赛后用虚高率复核每道题的得分异常,持续追踪新泄漏。三条规矩,把一次性清库升级成了长效机制。
这些措施背后的逻辑是:评测公平不只靠一次去重动作,而是一套持续演进的体系。去重报告让社区可以审计“分数可信度”——榜单可信度建立在透明的流程之上;私密留出集即使公开语料混入旧题,也能通过新旧题表现差识别污染;持续监控则对新增爬取数据定期复扫,防止二次污染。
一个被广泛认可的量化工具是“虚高率”:用去重前后两个模型在同一批题上的得分差,除以干净模型的得分。虚高率越高,说明该题泄漏越严重、榜单越不可信。评测方一旦发现某道题虚高率异常,应将其剔除或打上“疑似污染”标签,重新计分。这就是用数字守护公平的最后一道防线。
第二年大赛,小灶再次夺冠,成绩依旧亮眼。但这一次,没人怀疑它作弊——因为大家都知道,品控小组的传送带一直开着,评委菜单再也没有混进过菜谱库。评测的公平,正是这样被一格格阈值、一条条流程、一份份报告守护出来的。
- S_泄漏(污染模型得分)训练数据含重复样本的模型在评测集上的成绩。
- S_干净(去重模型得分)剔除重复样本后重新训练得到的成绩,代表真实水平。
- 差值两者相减得到因污染而虚高的绝对幅度。
- 归一化百分比除以干净分数再乘以 100%,消除基准差异,便于跨模型比较。
AI 应用场景
大模型预训练前的语料清洗
阶段:数据预处理 / 预训练
解决的问题:直接从互联网爬取的语料(如 C4、RefinedWeb)规模达万亿 token,难免混入 MMLU、GSM8K、HumanEval 等公开基准的题目。若不清理,模型“背题”式虚高,能力评估彻底失真。用去重流水线把语料与基准题集合逐一比对,污染样本剔除后再进预训练。
具体案例:某团队训练 70B 模型前,用 13-gram 精确命中 + MinHash Jaccard > 0.8 双规则对 1.4T token 语料扫描,剔除约 120 万条与评测集高相似的样本;重新训练后在 MMLU 上分数微降 0.3%,但在新发布的正规基准上反超对比组 1.8%,验证了真实能力的提升。
评测榜单发布前的公平性审计
阶段:评测与基准构建
解决的问题:评测方发布新榜单前,无法确认各个参赛模型是否“偷看”过题目。通过提供公开去重工具与重叠度报告,让参赛方自查训练集与评测集的重叠情况,保证横向对比公平,避免“背题”模型霸榜。
具体案例:某评测平台发布编程能力榜单时,同时给出 dedup 脚本:参赛方上传训练数据哈希或样本即可获得重叠报告。有团队自查发现 3.2% 训练样本与评测用例重合度超阈值,主动重训后再参赛,赢得了社区信任,榜单可信度大幅提升。
企业内部私有评测防泄漏
阶段:数据治理 / 安全合规
解决的问题:企业自建私有评测集用于模型验收,但训练数据往往来自第三方数据供应商,存在题面泄漏与版权双重风险。对企业内部数据包做去重扫描,确保私有题面没有混入训练数据,验收分数才算数。
具体案例:某金融科技公司上线智能客服前,将其 2 万条私有 FAQ 评测题与供应商的 500 万条训练语料比对,发现 37 条问法高度相似的样本,立即要求供应商剔除后重新交付,避免模型“背题”通过验收、上线后却在真实场景中翻车。
Python 演示
# -*- coding: utf-8 -*-"""简易去重演示: 用 n-gram Jaccard 相似度过滤与评测集重复的训练样本"""import re def ngrams(text, n=3): text = re.sub(r"\s+", "", text) return {text[i:i + n] for i in range(len(text) - n + 1)} def jaccard(a, b): if not a or not b: return 0.0 inter = len(a & b) union = len(a | b) return inter / union def dedup(train_samples, eval_samples, threshold=0.5, n=3): eval_sets = [ngrams(e, n) for e in eval_samples] kept = [] removed = [] for sample in train_samples: sample_set = ngrams(sample, n) max_sim = max((jaccard(sample_set, e) for e in eval_sets), default=0.0) if max_sim >= threshold: removed.append((sample, max_sim)) else: kept.append(sample) return kept, removed def main(): eval_samples = [ "小明去超市买了苹果和香蕉", "北京是中国的首都,故宫位于北京", ] train_samples = [ "小明去超市买了苹果和香蕉", "小明去超市买了苹果和香蕉(改写版)", "小红去公园散步,天气很好", "北京是中国的首都,故宫位于北京,天坛也很著名", "机器学习是人工智能的一个重要分支", ] kept, removed = dedup(train_samples, eval_samples) print("保留样本:") for s in kept: print(" " + s) print("剔除样本:") for s, sim in removed: print(" " + s + " | 最大相似度: " + str(round(sim, 3))) if __name__ == "__main__": main()
eval_sets = [ngrams(e, n) for e in eval_samples]提前把评测集每条样本切成 n-gram 集合,避免循环内重复计算。sample_set = ngrams(sample, n)把当前训练样本也切成片段集合,准备与所有评测样本比对。max_sim = max((jaccard(sample_set, e) for e in eval_sets), default=0.0)与所有评测样本逐一比较,取最大相似度作为“污染嫌疑值”。if max_sim >= threshold:嫌疑值超过阈值即判定为重复,进入剔除清单。removed.append((sample, max_sim))被剔除的样本连同相似度一起记录,便于事后抽检复核。if __name__ == "__main__":程序入口,直接运行本文件即可看到演示结果。
常见误区
误区去重?不就是把训练集和评测集里一模一样的样本找出来删掉吗?改个标点、加个空格应该就没事了吧。
正解完全相同的样本属于“精确去重”,但污染的主力是“模糊重复”:换同义词、调整语序、插入前后缀、翻译改写,肉眼看着不像,n-gram 重合度却极高。只做精确去重,等于只抓了明摆着抄的人,放走了所有改写者。工业界去重必须用 n-gram Jaccard、MinHash 或向量相似度把“高度相似”也筛出来。
为何常见:“一样”是最直观的重复定义,初学者容易把复杂问题简化成字符串相等,不知道相似度度量能抓改写。
误区去重阈值当然越高越好,标准越严格,漏掉重复样本的概率就越低,应该更安全吧?
正解阈值高意味着只有几乎完全一致的样本才会被剔除,大量“七分像”的改写样本会漏进训练集,污染依然存在并继续虚高分数。真正的安全是在漏网与误伤之间取平衡:先抽样标注看相似度分布,再在两类样本交叠处取阈值,使加权风险最小。
为何常见:日常思维里“标准严格=结果可靠”,忽略了检测问题特有的两类错误此消彼长。
误区去重是为了让排行榜好看,删掉的都是和考试题重复的数据,对模型训练本身没什么价值。
正解去重同时影响训练:重复的评测样本是“记忆包袱”,模型把参数花在背答案上,换到分布外数据就露馅;删掉它们后,模型被迫学习通用规律,泛化与鲁棒性往往更好。当然数据量折损也真实存在,所以结论是“评测公平与训练质量双收益,需权衡数据损失”。
为何常见:人们习惯从评测榜单视角看问题,忘了训练数据质量与模型真实能力直接挂钩。
误区我们已经在发布前用最新评测集清洗过语料了,以后都不用再管了。
正解训练语料在持续爬取更新,评测集也在迭代扩充,新爬的数据完全可能再次混入新题;旧题还可能以翻译、改写形式回流。正确做法是把去重做成持续流水线:每次新增语料都过一遍评测集索引,定期复扫全量数据,配合虚高率监控发现异常。
为何常见:把数据看成静态资产,忽略了互联网语料和评测基准都是动态演化的。
误区去掉的样本越多,训练数据越少,模型一定越笨,所以去重应该适可而止。
正解去重删除的是“与评测集重复、信息量低”的样本,保留的是高多样性的正常语料,数据“质”的提升往往抵消“量”的下降。若因阈值过低导致误伤大量正常数据,正确做法是调高阈值或细化规则(如按来源、按质量分层),而不是放弃去重。
为何常见:把去重等同于盲目删数据,混淆了数据数量与数据质量对模型的影响。
面试题
Q1. 评测数据污染最直接的危害是什么?
- A.导致训练速度变慢
- B.导致评测分数虚高← 正确答案
- C.导致模型结构变复杂
- D.导致推理显存占用增加
答案:B。污染让模型背下题目答案,评测分数虚高,无法反映真实推理能力;训练速度、网络结构和显存占用与污染没有必然关系。这就像小灶背熟评委菜单,端出的菜惊艳但没真厨艺。
Q2. 在训练流程中,去重(Dedup)通常发生在哪个阶段?
- A.数据预处理阶段← 正确答案
- B.模型推理阶段
- C.参数微调阶段
- D.结果评估阶段
答案:A。去重属于数据处理工序,在语料送入预训练或微调之前执行,相当于品控小组在食材入库前清库;推理、评估阶段并不会修改训练数据。
Q3. 下列哪项可以用来量化两段文本的相似度?
- A.Jaccard相似度← 正确答案
- B.交叉熵损失值
- C.梯度下降步数
- D.批量大小设定
答案:A。Jaccard 通过交集除以并集度量集合重叠,是 n-gram 去重的核心指标;交叉熵是训练损失,梯度步数与批量大小是训练配置参数,都不能直接度量文本相似。
Q4. 去重阈值设得过高(如 0.95)的主要风险是什么?
- A.误删过多正常训练样本
- B.放过改写后的重复样本← 正确答案
- C.误判评测集题目为重复
- D.导致评测集规模变大
答案:B。阈值越高判定越严,只有几乎完全重合的样本才被剔除,轻度改写、换序的重复样本会漏网;误删是低阈值的问题,评测集本身规模也不会因阈值变化而改变。
Q5. n-gram 去重中,n 值取较大时通常会导致什么?
- A.匹配更宽松召回率更高
- B.匹配更严格但漏网增多← 正确答案
- C.相似度计算复杂度更低
- D.对评测公平性没有任何影响
答案:B。n 越大片段越长越独特,只有完全一致的片段才被认为重合,匹配变严格,轻微改写就测不出来,漏网增多;召回率下降而非升高,计算量也上升而不是下降。
Q6. 关于去重对模型训练效果的影响,下列说法正确的是?
- A.去重必然会导致模型能力大幅下降
- B.去重能减少死记硬背并提升泛化← 正确答案
- C.去重与模型泛化能力完全没有关系
- D.去重只能应用在预训练前的数据上
答案:B。去除与评测集重复的样本后,模型不再“背题”,容量转向学习可泛化规律,通常提升分布外表现;数据量折损可能带来轻微影响但并非必然大幅下降,去重也不限于预训练前。
Q7. 去重后重新训练,模型在评测集上的得分与未去重时几乎相同,最合理的解释是?
- A.去重流程本身没有正确执行
- B.污染恰好被其他噪声完全抵消
- C.该模型本就没有从污染中获益← 正确答案
- D.评测集一定不包含任何泄漏
答案:C。当污染样本占比极低或模型记忆能力有限时,删掉重复样本不会改变成绩,说明它之前也未从污染获益;“没执行”和“无泄漏”过于绝对,噪声恰好等量抵消更不可能。
Q8. 完整的跨数据集去重流程通常包含哪些环节?
- A.收集评测集题目与参考答案← 正确答案
- B.构建相似度检索索引或签名← 正确答案
- C.调整模型的网络层数与宽度
- D.流式扫描训练语料并剔除← 正确答案
答案:ABD。去重流程是数据预处理链路:先收集评测集,再建索引/签名,然后流式扫描语料剔除重复样本,最后抽检验证;调整网络结构属于模型设计,与数据去重无关。
Q9. 下列哪些属于评测公平性的保障措施?
- A.公开去重策略与阈值设置← 正确答案
- B.发布去重前后的对比报告← 正确答案
- C.使用私有留出集做保密评测← 正确答案
- D.提高推理时使用的批处理大小
答案:ABC。公示策略、发布对比报告、使用保密留出集都能提升评测可信度与可审计性;批大小是推理性能参数,与评测公平性无关。
Q10. 关于相似度度量与阈值设定,下列说法正确的有?
- A.Jaccard值越大表示文本越相似← 正确答案
- B.阈值越高误伤越少但漏网越多← 正确答案
- C.MinHash可以高效估计Jaccard← 正确答案
- D.阈值设定与模型的泛化能力无关
答案:ABC。Jaccard 度量集合重合,值越大越像;阈值升高会减少误删但放过改写样本;MinHash 用签名近似估计 Jaccard,大幅降低比对成本。D 错误:阈值决定删多删少,直接改变训练数据构成,从而影响泛化能力。