技术博客

数据清洗流水线:去重、过滤、脱敏与 MinHash 近重复检测

第 110 / 147 篇 · 2026-02-18 · ai · 数据工程去重MinHash

CommonCrawl 原始爬取里大约有三分之一是近乎重复的页面——同一个论坛帖被镜像站爬了八遍,电商模板页只换了商品名。不去重就训练,等于花几十万美元让模型把 boilerplate 背八遍。这篇文章按数据流水线的实际顺序过五道工序,重点推导 MinHash 近重复检测的数学,把阈值选择的直觉公式化。

流水线总览与成本账本

原始爬取 → ① trafilatura 抽正文 → ② 语言识别 → ③ 启发式过滤
        → ④ 三级去重(exact → near → semantic)→ ⑤ 去污染 → ⑥ PII 脱敏
        → 可训练语料

成本结构值得先看:FineWeb 数据集从 96TB 原始爬取提取出约 15TB 有效文本,体积砍掉 84%,这 84% 里没有一分钱训练价值。各道工序的性价比差异很大——语言识别和启发式过滤用 CPU 几小时就能跑完 PB 级数据,近重复去重需要上千核天的算力,语义去重(embedding 聚类)最贵,工业界只在最后阶段做。决策顺序:先做便宜的,把语料砍到剩 20%,再用贵的工序处理剩下的。

数据清洗漏斗:每道工序砍掉多少体积(FineWeb 实测口径) 原始爬取 96TB 正文提取+语言识别 剩 ~45TB 启发式质量过滤 剩 ~28TB MinHash 去重 剩 ~18TB 去污染 +PII MinHash + LSH 参数账本(对每篇文档) ① 切成 5-gram 词组(shingle)→ 每个词组哈希成整数 ② 取 128 个哈希函数的最小值 → 128 维签名向量 ③ 签名切成 b=32 带 × r=4 行,同带全等 → 候选对 碰撞概率 1−(1−s⁴)³²:s=0.3 时 ≈0.22,s=0.8 时 ≈1.00 阈值可调:b·r 固定下改切法,曲线越陡越省后续 Jaccard 验证

启发式过滤:便宜但别迷信

启发式过滤的规则来自对低质语料的统计观察:FineWeb 用的规则包括文档长度分布(过短的多是导航碎片)、字母占比(大量页面是 base64 或乱码)、重复行比例(模板页的标志)、以及困惑度过滤(用一个小 LM 给文档打分,过滤高分尾部)。CCNet 最早系统化这套做法。规则各砍掉多少有公开的消融,但过滤的边际收益在收窄——最新的工作(FineWeb-Edu)发现用"教育价值"分类器代替手工规则能多榨出几个点的下游收益,说明手工启发式已经接近它的信息上限。

一个实用的提醒:过滤规则要按领域分别调。Reddit 评论的平均长度天然比维基短,用统一长度阈值会把有用的口语语料误杀一半。工业界的做法是每条规则都先在子集上测误杀率,超过 5% 就回退这条规则或加豁免条件。

MinHash:把集合相似度压成 128 个整数

去重的核心问题是:两个文档的集合相似度(Jaccard)

$$ J(A,B) = \frac{|A \cap B|}{|A \cup B|}, $$

$A$、$B$ 是文档的词组(shingle)集合。直接算需要对每对文档求交并,$O(N^2)$ 不可行。MinHash 的观察是:对集合 $A$ 和哈希函数 $h$,$\Pr[\min h(A) = \min h(B)] = J(A,B)$。证明只需一行:所有元素中最小哈希值落在交集里的概率恰好是交并比。用 $k$ 个独立哈希函数取最小值,得到 $k$ 维签名,两个签名的逐维相等率就是 $J$ 的无偏估计,方差 $J(1-J)/k$。

$k=128$ 时仍有 $O(N^2)$ 次签名比较的问题,这里引入 LSH(局部敏感哈希):把 128 维签名切成 $b$ 带,每带 $r$ 行($br = k$)。两个文档只要在任一带全等就进入候选对。碰撞概率为

$$ P(\text{候选}) = 1 - (1 - J^r)^b. $$

这个 S 形曲线就是调参的依据。取 $b=32, r=4$:$J=0.3$ 时 $J^4 \approx 0.008$,$P \approx 1-0.992^{32} \approx 0.22$,只有两成相似度低的文档对会进入候选;$J=0.5$ 时 $P \approx 0.87$;$J=0.8$ 时 $P \approx 1.00$,真正的近重复几乎必然命中。要压低端候选率就把曲线变陡:固定 $br=128$,增大 $r$ 减小 $b$(如 $b=16, r=8$),$J=0.3$ 的候选率降到约 0.05,代价是 $J=0.7$ 的召回从近 1 掉到 0.94 左右。工程上的平衡点选在 $J \approx 0.8$ 附近——经验上 0.8 以下的相似文档对训练基本是重复的负价值,0.8 以上必须去。选完候选对后仍要回算精确 Jaccard(对候选对算 $A \cap B$),LSH 只负责把比较次数从 $10^{16}$ 压到 $10^9$ 量级。

去污染与 PII:评测公平和合规底线

去污染是清洗流水线里唯一直接影响评测可信度的工序:如果 GSM8K 的测试题混进了训练语料,数学能力的评估就失效了。标准做法(GPT-3 定下的):对评测集做 n-gram(8-gram 或 13-gram)抽取,与训练语料哈希比对,命中即整篇删除。需要注意的是 n-gram 长度选择是精度的旋钮——太短误杀(常见短语撞车),太长漏检(改几个词就绕开)。OpenAI 后续工作承认过 13-gram 仍有漏网,所以现在还有人用嵌入相似度做第二道(把评测题编码后与语料 embedding 检索,余弦超阈值即污染)。n-gram 便宜可全量,embedding 贵只能抽查,两道并用是当前共识。

PII 脱敏是合规要求而非质量要求:邮箱、电话、身份证号在预训练语料里出现,模型有一定概率在生成时复述真实个人信息。做法是用规则 + NER 模型打标后做掩码替换(<EMAIL> 占位符)。误判代价低(掩码掉一个邮箱不影响文本流),漏判代价高,所以阈值宁松勿紧。

小结

数据清洗的经济学很简单:每道工序砍掉的那部分数据,训练价值趋近于零,但留着会稀释有效 token 密度、放大记忆化风险。MinHash + LSH 是近重复检测的工程正解——Jaccard 的 MinHash 无偏估计把相似度压成定长签名,LSH 带切法决定召回-误报权衡,$1-(1-J^r)^b$ 是调参的唯一公式。启发式过滤便宜但接近信息上限,去污染决定评测是否可信,PII 是合规底线。清洗不是预处理杂活,是预训练收益的一部分。