AI 基建
0%
第一部分 · 基座模型的形成 · 第 6 章

数据筛选与质量

作者Changkun Ou
阅读时长约 14 分钟

第 5 章 定下的是算力预算;这一章要问的是,用什么语料把它填满。算力和架构一旦固定,把强模型和平庸模型拉开差距的,就是语料。从原始网络字节到词元 id 分片,这条路径决定模型会学到哪种分布,哪些能力会训练过度或训练不足,也决定后面的评测数字还能不能被信任。

语料是一个系统,不是一段脚本

一次预训练消耗的算力预算,由 第 5 章 设定,是固定的。这笔预算换来一个词元数,而填满它的语料,是影响最终质量最大的环节,也是最难从公开配方里照搬过来的部分。麻烦在于,这里的失败是无声的:一份重复的分片、一个把某种方言整体剔除的过滤器、一个通过合成数据步骤混入的基准题,都不会抛出任何错误,却都要等到评估时才浮现。到那时再诊断,代价高昂,而且往往不重跑就无法挽回。所以语料必须当成一个系统来建:每个阶段都可审计,它与栈中其余部分的每一次交接,都是一份显式的契约。

其中有两次交接,约束着本书的其余部分。词表会进入 第 7 章 里的架构,本章对分词器(tokenizer)只是点到为止,它的设计留到那里展开。去污染(decontamination)报告,也就是说明哪些基准重叠已从训练语料中移除的审计记录,会进入 第 47 章 里的评估,而本章据以核对的评估清册则由评估层提供。

这不是一个单纯写脚本的问题。下文所讲的一切,都在 PB 量级上运行,是跨大规模 CPU 集群的分布式批处理或流处理作业(Apache Spark、Ray,或自研的 MapReduce 式集群),与 GPU 训练集群相互独立,且位于它的上游。难的是吞吐、确定性和可恢复性,而不是单文档层面的算法。重跑必须产出逐字节一致的分片,否则数据配比和去污染契约就无从验证。

明确这些契约之后,下一步就是跟着一个字节走:从开放网络出发,穿过一道道决定它去留的收窄过滤器,然后退一步,看那三项很早就被锁死的决策、那份保护数字的契约,以及解释这个领域为何至今仍在争论这一切的两条历史。

一个字节穿过逐级收窄的过滤器

这条流水线就是一连串逐级收窄的过滤器。相对它所供给的那次训练,每一级都很廉价,而且特意安排成让最廉价的削减最先发生。

A 原始网页 CommonCrawl B 抽取文本 + 语言识别 A->B D 清洗 + 归一化 B->D C 精选语料 / 代码 / 多语言 C->D E 去重 精确 / 模糊 D->E F 质量过滤 启发式 + 分类器 E->F G 合成数据 增强 F->G H 混合配比 + 课程顺序 G->H I 去污染 对照评测登记表 H->I J 分词 见 sec-tokenization I->J K 词元 id 分片 J->K
图 6.1. 筛选流水线是一连串逐级收窄的过滤器,最廉价的削减最先进行,最终落到词元 id 分片。每一阶段都是一次可审计的交接。

字节从哪里来

主体数据来自网络。CommonCrawl 是原始输入:WARC/WET 抽取、样板内容剥离、语言识别,以及 URL 和主机层级的过滤。CommonCrawl 既原始又嘈杂,价值在于后续流水线,而非爬取数据本身。围着这个网络核心的,是各类精选来源:书籍、论文、百科和参考类文本,带许可证与质量信号的源代码,以及按刻意设定的比例配进来的非英文文本。每一类来源的许可、质量和去重特性都不一样,而它们都在争抢同一份词元预算。

任何过滤之前,先把字节规范化。清洗和归一化包括 Unicode 归一化、文本抽取伪影的修复、PII 处理,以及毒性和安全的预过滤。目标是移除低质量内容,同时别把合理的分布多样性也一并抹掉:模型要想泛化,正需要见到这些语域、方言和领域。

第一道削减:去重

去重在三种粒度上使用三种机制。精确哈希移除完全相同的文档。后缀数组或子串方法,去掉那些近重复的片段,它们藏在本来各不相同的文档内部。最小哈希(MinHash) 配合局部敏感哈希(LSH),在语料规模上做模糊的文档级去重:它从一小组哈希后的 shingle(文档里相互重叠的 k 词片段)估出文档间的 Jaccard 相似度(两篇文档共享的片段占比),于是代价是次平方,而不是全配对。去重回收被浪费的算力,也减少逐字记忆。这里长期有一处取舍:去重越激进,就越可能连真正独特的内容也一起删掉。

去重不只是省钱,证据也支持这一点。Lee 等人发现,对训练数据去重会让模型变好,而不只是变便宜:它削减记忆、改善留出损失(在模型未曾训练过的数据上度量的误差)(Lee et al. 2022)。SemDeDup 把这个想法推进到嵌入空间,移除表层哈希漏掉的语义近重复 (Abbas et al. 2023)。贯穿其中的线索是:冗余并不中性,它会主动让模型退化,所以移除冗余本身也是一种质量过滤。

图 6.4 说明了 MinHash 配合 LSH 为何能避免全配对的成本爆炸:每篇文档被压成一个短签名,LSH 的分带把相似签名分进共享的桶,而完整的 Jaccard 估计,只对那些已经进入同一个桶的少数文档计算。

图 6.2. 十五篇文档,其中几篇互为近似重复,按各自的 MinHash 签名分进 LSH 的桶。只有共享一个桶的文档(高亮)才成为候选对、去做一次完整的 Jaccard 检查,于是代价是次平方,而不是全配对。多加桶能收紧阈值、削掉假碰撞;真正的近似重复仍会落到一起。示意性。

运行下面这段代码,看 最小哈希 签名怎样只凭几个哈希就估出 Jaccard 相似度,以及估计如何随 num_perm 增大而变准。

import numpy as np

rng = np.random.default_rng(0)
universe = 5000                       # shingle 词表大小
A = set(rng.choice(universe, 800, replace=False).tolist())
B = set(A) ^ set(rng.choice(universe, 400, replace=False).tolist())
true_j = len(A & B) / len(A | B)      # 精确 Jaccard

def minhash_estimate(A, B, num_perm):
    seeds = rng.integers(1, 2**31 - 1, size=num_perm)
    a = np.array(sorted(A)); b = np.array(sorted(B))
    hits = 0
    for s in seeds:                   # 哈希排列的最小值就是 MinHash
        if (a * s % universe).min() == (b * s % universe).min():
            hits += 1
    return hits / num_perm            # P(最小值碰撞) = Jaccard

for num_perm in [16, 64, 256, 1024]:
    est = minhash_estimate(A, B, num_perm)
    print(f"num_perm={num_perm:>5}  估计={est:.3f}  真实={true_j:.3f}")

图 6.3 把这条成本论证量化了。朴素的全配对比较随语料规模呈平方增长,在 PB 量级上毫无希望;而 LSH 只比较那些本就共享同一个桶的文档,把候选数量压得接近线性。

2026-06-21T23:29:35.309400 image/svg+xml Matplotlib v3.11.0, https://matplotlib.org/ 1 0 3 1 0 4 1 0 5 1 0 6 1 0 7 1 0 8 1 0 9 语料文档数 (n) 1 0 4 1 0 6 1 0 8 1 0 1 0 1 0 1 2 1 0 1 4 1 0 1 6 1 0 1 8 两两比较次数 全量两两比较 O(n²) MinHash + LSH ≈ O(n)
图 6.3. 模糊去重成本的示意对比。全配对比较随语料规模呈 O(n 平方) 增长,而 MinHash 配合 LSH 因只比较落入同一分带桶的文档而保持接近线性。理想化计数,据 Broder (1997) 与 Lee et al. (2022)。
A 文档文本 B shingle (k-gram 集合) A->B C MinHash 签名 (num_perm 个哈希) B->C D 切分为 LSH 分带 C->D E 是否与已保留文档 共享桶? D->E F 插入签名, 保留文档 E->F G 在桶内候选上 估计 Jaccard E->G H 是否超过 阈值? G->H H->F I 按近重复丢弃, 记入清单 H->I
图 6.4. 在语料规模上用 MinHash 配合 LSH 做模糊去重。只有共享同一 LSH 桶的文档才会被比较,因此代价是次平方而非全配对。据 Broder (1997) 与 Lee et al. (2022)。

第二道削减:质量过滤

通过去重的内容,还得跨过一道质量门槛,而这道门槛由两个家族来设。启发式过滤基于规则:长度、符号与词的比例、重复度、停用词是否出现,以及一个由参考模型给出的困惑度阈值(即该模型对这段文本有多意外,困惑度越低越说明文本流畅)。它们廉价、可审计,对明显的垃圾召回率高,但在边缘情形下脆弱。分类器过滤器是学出来的:一个模型用每篇文档对照一份「优质」文本的参考来打分,比如训练一个分类器,去区分精选文本和原始网络文本。分类器精确度更高,却带着一个结构性风险,它会把参考集对「质量」的定义,编码进整套语料。这种参考困惑度过滤,可以直接追溯到 CCNet,它把语言识别和一个来自参考语言模型的困惑度分数配在了一起 (Wenzek et al. 2020)。

很早就被锁死的决策

等字节通过质量过滤,单文档层面的处理就结束了。剩下的都是全局性的:怎么组合各个来源,怎么给它们排序,要不要再生成更多文本。这些决策说起来很轻,改起来却很重,因为每一项都牵制着其余几项。

数据配比是网络、代码、精选、多语种之间的比例,再加上各来源的权重。它可以手工调,可以从小规模的代理消融实验(受控地只改一个变量,以测量它的影响)外推,也可以直接拿去优化。DoReMi 把配比选择刻画成一个分组的分布鲁棒优化:先训一个小代理,用它找到让各领域最坏情形超额损失最小的权重,再把这些权重套到完整训练上 (Xie et al. 2023)。配比很早就锁死、事后再改代价高昂,因为一改它,课程编排就得重新推导,往往还要把代理消融实验重跑一遍。

课程编排是数据在训练过程里的排序和分阶段:由易到难、按领域分阶段,或者把一份高质量切片留到后期。这是数据层内部的排序。它和退火阶段不是一回事,后者在训练接近末尾时给高质量数据加权,属于中段训练,放在 第 11 章 讨论。

合成数据是模型生成和模板化出来的文本:对网络文本做改写或增广、教科书式生成,以及蒸馏目标。其理由是:少量稠密、质量高、贴合分布的文本,价值可能远高于它在原始网络里所占的词元比例。它在填补能力空白上很有力,第 23 章 会把它当作一种一等的后训练工具来谈。风险则是分布收缩、事实漂移,以及把评估内容带回训练里。正因为最后这项风险会直接影响随后那份契约,合成数据也恰恰是流水线最需要下一阶段严格把关的地方。

去污染作为一份契约

去污染包含几件事:拿训练文档去对照评估清册做 N-gram 或子串重叠检测、一个重叠阈值、一个丢弃或标记的决策,以及一份作为契约交给评估的报告。这个阶段让数据层直接影响评测层。交接的是这份报告,而不是一套共享的实现。

阈值不是一个自由参数。N-gram 重叠检测本身可以被绕过:改写过的基准样本会漏过表层匹配,这恰恰是阈值和方法要做成一份谈判出来的契约、而非一个私有默认值的原因 (Yang et al. 2023)。阈值太松,会泄露基准、虚抬分数。阈值太严,会过度移除合理的近重复内容、让语料缩水。无论哪种,这个决策都属于本章和 第 47 章 之间的边界,而不属于数据团队内部。

下层约束

评估层对本层提出了一道硬约束。去污染阈值不是数据团队的偏好:它由 第 47 章 定义并必须提供的评估清册规定。如果评估不说明哪些留出集需要保护,本章就没法保证日后报告出来的数字可靠。最坏情形的失败,是一次污染泄露:它可能穿过一处去重缺口、一条合成流水线,或一份内嵌了基准任务的智能体轨迹记录,一次性提高每一个下游分数。去污染契约存在的意义,正是为了让一个下层无法无声地影响一个上层。

这套配方怎么走到今天:两条历史

从拼装语料到把流水线做成产品

早期的语料是拼装出来的,不是工程化出来的。The Pile 从二十二个多样来源里精选出 800GB,并把组成部分清楚列出 (Gao et al. 2020)。为 T5 而建的 C4 表明,对 CommonCrawl 施加少数几条启发式清洗规则,就已经能改动下游质量 (Raffel et al. 2020)。把流水线做成产品的转向,始于 CCNet,它把语言识别和一个来自参考语言模型的困惑度过滤结合起来 (Wenzek et al. 2020),接着是 RefinedWeb,它的主张更明确:单凭网络数据,只要过滤和去重足够严格,就能匹敌甚至胜过精选语料 (Penedo et al. 2023)。FineWeb 借助公开的消融实验把这一点推得更远,这些实验固定算力和架构、只改数据,把语料构建从经验法则(folklore)变成了一门可度量的科学 (Penedo et al. 2024)。

合成的转向

合成的转向是靠两个结果到来的。TinyStories 表明,一份狭窄、完全合成的语料,能教会小模型连贯的英文 (Eldan and Li 2023)。由「Textbooks Are All You Need」开启的 phi 系列主张,教科书质量的合成与过滤数据,能用惯常词元数的一个零头达到强推理 (Gunasekar et al. 2023)。Rephrasing the Web(WRAP)给出了成本更低的版本:把已有的网络文本改写成质量更高的文风,而不从头生成,从而在不凭空造内容的前提下获得算力和数据上的效率 (Maini et al. 2024)。最新、也记录得最少的来源,是智能体轨迹记录:工具使用轨迹和经过验证的多步轨迹,被回收成训练信号,ToolBench 这样的数据集是它的先声 (Qin et al. 2023)。那里悬而未决的问题,包括来源出处、对源模型自身输出的去重,以及内嵌评估任务带来的污染。

争议所在

追逐规模还是追逐质量,没有定论。一派沿 RefinedWeb 和 FineWeb 一脉而来,认为激进过滤和去重后的网络数据已经够用,一旦过滤做得够好,精选语料添益甚微。另一派沿 phi 系列一脉而来,认为合成的教科书质量数据,其价值远高于词元占比,语料的未来是被生成的,而不是被爬取的。这场分歧之所以活跃,是因为两种立场意味着不同的基础设施、不同的成本结构、不同的污染风险,也因为重合成的配方最难可靠评估:生成这些数据的,正是那批离基准很近的模型。把合成占比当成一个在多样性和可控性之间做出的选择,而不是一个已经解出来的比值。

图 6.5 勾勒了为什么这是个结构性抉择,而不是一个单一可调的比值:每一派都会分叉出不同的栈、成本结构和污染风险。

Q 下一批词元从哪里来? Scale 规模派 (RefinedWeb, FineWeb) 强力过滤和去重网络数据 Q->Scale Quality 质量派 (phi 系列) 生成教科书级数据 Q->Quality ScaleInfra 基础设施:大型 CPU 过滤与去重集群 Scale->ScaleInfra ScaleCost 成本:爬取加 分类器多轮处理 Scale->ScaleCost ScaleRisk 风险:泄露穿过 去重缺口 Scale->ScaleRisk QualInfra 基础设施:生成模型 进入数据回路 Quality->QualInfra QualCost 成本:用推断 合成词元 Quality->QualCost QualRisk 风险:评估污染、 漂移、分布收缩 Quality->QualRisk
图 6.5. 规模与质量之争为何未定论:每一派都意味着不同的栈、成本结构与污染风险,因此这一抉择并非单一可调的比值。

权衡项与失效模式

上文每一个阶段都是一个决策点,方向错了,都会无声地失败。这些决策值得放在一起点名,因为它们彼此牵连。

  • 数量对质量。 更多词元,只有在它们不是垃圾或重复时才有帮助。越过某个点,激进的过滤和去重就会胜过单纯堆量,正如 图 6.6 所示:原始网络数据的留出损失,会在新增词元大多只是重复模型见过的内容时趋于平坦,而同样的算力用于去重并过滤后的词元时,损失仍在下降。难的是知道对给定算力预算而言那个点在哪,而那个点会随着 第 5 章 设定的预算一起移动。
2026-06-21T23:29:37.189833 image/svg+xml Matplotlib v3.11.0, https://matplotlib.org/ 1 0 0 1 0 1 1 0 2 1 0 3 消耗词元数(对数刻度) 留出损失 原始网页(重复且嘈杂) 去重 + 过滤
图 6.6. 数量与质量权衡的示意。原始网络数据的留出损失因重复与嘈杂词元几乎不带来新信号而较早趋平,而把同等算力花在去重并过滤后的词元上则持续下降。理想化曲线,非实测损失,据 Lee et al. (2022) 与 Penedo et al. (2024)。
  • 去重的激进程度。 更强的模糊去重能消掉记忆风险和算力浪费,但也可能删掉合理而稀有、却独特的内容。阈值是在召回与精确之间做权衡,没有一个普适正确的设定。
  • 启发式对分类器过滤。 启发式成本低、可审计、偏见也轻,但精度有限。分类器精确,却会把它参考集的偏见引入整套语料,成片地移除某些语域、方言或领域。
  • 合成占比。 合成数据能以较低成本填补空白,但有分布收缩、事实漂移和评估污染的风险。这个比例,是在多样性和可控性之间权衡。
  • 去污染的严格程度。 阈值太松会泄露基准、虚抬分数。阈值太严会过度移除合理的近重复内容、让语料缩水。这个阈值是一项契约条款,不是一个内部细节。

这些失效模式值得逐一点名,因为它们各在不同时刻出现。一次污染泄露会虚抬结果,就算能被发现也很晚。一处去重缺口会浪费算力、提高记忆风险,而过度去重又会无声地移除稀有内容。过滤器偏见放大,会在整套语料上移除合理的多样性。合成数据导致分布收缩或漂移,会收窄分布,或把生成器的错误传播下去。配比失误会让某项能力训练不足或训练过度,而由于配比很早就锁死、又只在评估时才浮现,它是诊断和重做代价最高的那一个。

确定性纪律

设计决策之后,落到运维上就是确定性纪律。因为数据配比和去污染都是契约,每一个阶段都必须逐字节可复现。具体到实践,这意味着内容寻址的输入、被钉死的过滤阈值和模型版本,以及一份清单,为每个输出分片记下产生它的确切变换。一个有代表性的去重步骤,是用 MinHash 和 LSH 做模糊文档匹配,下面针对其方法、而非任何单一代码库来勾勒:

# 模糊去重:按 LSH 分桶,再在桶内丢弃近重复。
def dedup(docs, threshold=0.8, num_perm=128):
    seen = LSHIndex(threshold=threshold, num_perm=num_perm)
    for doc in docs:
        sig = minhash(shingles(doc.text), num_perm=num_perm)
        if not seen.query(sig):      # 还没有保留过近重复
            seen.insert(doc.id, sig)
            yield doc                 # 否则丢弃,并记入清单

去污染步骤是同样的形状、只换一个索引:为评估清册里的每一项构建 n-gram 签名,然后把任何重叠超过契约阈值的训练文档丢弃或标记,并把被移除文档的数量和身份,写进评估所使用的那份报告。

延伸阅读

  • Penedo et al., “The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scale,” 2024. arXiv:2406.17557
    FineWeb 是一个从 96 个 Common Crawl 快照中提取的 15 万亿词元预训练数据集,采用消融实验驱动的过滤策略与逐快照最小哈希去重,性能优于其他公开预训练数据集;FineWeb-Edu 是 1.3 万亿词元的教育子集,在 MMLU 和 ARC 上表现显著更好。
  • Penedo et al., “The RefinedWeb Dataset for Falcon LLM: Outperforming Curated Corpora with Web Data, and Web Data Only,” 2023. arXiv:2306.01116
    RefinedWeb 表明,对 CommonCrawl 进行严格过滤与去重后得到的五万亿词元纯网页数据,可训练出超越使用精心策划语料库(如 The Pile)所训练的大语言模型。
  • Wenzek et al., “CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Data,” 2020. aclanthology.org
    CCNet 是一条自动化流水线,通过去重、语言识别和基于维基百科困惑度的过滤,从 Common Crawl 中提取大规模高质量单语数据集。
  • Lee et al., “Deduplicating Training Data Makes Language Models Better,” 2022. aclanthology.org
    对大语言模型训练数据去重可将逐字记忆率降低十倍、减少训练-测试集重叠,同时以更少训练步骤达到相同或更高的准确率。
  • Abbas et al., “SemDeDup: Data-efficient Learning at Web-scale through Semantic Deduplication,” 2023. arXiv:2303.09540
    SemDeDup 利用预训练模型的嵌入向量识别并去除语义相似但非完全相同的重复样本,可将网络规模训练数据减少 50
  • Xie et al., “DoReMi: Optimizing Data Mixtures Speeds Up Language Model Pretraining,” 2023. openreview.net
    DoReMi 在小代理模型上应用组分布鲁棒优化,自动确定预训练数据的领域混合比例,使 8B 模型下游准确率提升 6.5
  • Gao et al., “The Pile: An 800GB Dataset of Diverse Text for Language Modeling,” 2020. arXiv:2101.00027
    The Pile 是一个由 22 个多样化来源组成的 825 GiB 英语文本语料库,旨在提升大语言模型预训练的跨领域泛化能力。
  • Raffel et al., “Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer” (T5 / C4), 2020. jmlr.org
    T5 提出统一的文本到文本框架,将所有自然语言处理任务转化为同一格式,并系统比较预训练目标、模型架构与数据规模,在多个基准上达到最优水平。
  • Soldaini et al., “Dolma: an Open Corpus of Three Trillion Tokens for Language Model Pretraining Research,” 2024. aclanthology.org
    Dolma 是一个开放的三万亿词元英语预训练语料库,来源涵盖网页、科学论文、代码、图书、社交媒体和百科内容,并附完整文档和数据策划工具包。
  • Gunasekar et al., “Textbooks Are All You Need” (phi-1), 2023. arXiv:2306.11644
    phi-1 是一个 1.3B 参数的代码大语言模型,仅用 7B 词元的教科书级高质量数据训练,在 HumanEval 上达到 50.6
  • Eldan & Li, “TinyStories: How Small Can Language Models Be and Still Speak Coherent English?,” 2023. arXiv:2305.07759
    TinyStories 提出一个由简单短故事构成的合成数据集,证明参数量低于 1000 万的语言模型也能生成流畅连贯的英文文本并涌现出推理能力。
  • Maini et al., “Rephrasing the Web: A Recipe for Compute and Data-Efficient Language Modeling” (WRAP), 2024. arXiv:2401.16380
    WRAP 方法用指令微调的 LLM 将嘈杂网页文本改写为多种风格的合成数据,与在原始网页语料上预训练大语言模型相比,可将所需计算量减少约 3 倍、数据量减少约 5 倍。
  • Yang et al., “Rethinking Benchmark and Contamination for Language Models with Rephrased Samples” (LLM decontaminator; on n-gram overlap thresholds and their limits), 2023. arXiv:2311.04850
    本文表明改写的基准测试样本(改述或翻译)可绕过 n-gram 与嵌入式去污染检测,并提出一种基于大语言模型的去污染方法,用于发现预训练数据集中的此类污染。
  • Qin et al., “ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs” (ToolBench tool-use trajectories as training data), 2023. arXiv:2307.16789
    ToolLLM 构建了包含 16,464 个真实 API 的指令微调数据集 ToolBench,并在此基础上对 LLaMA 进行监督微调得到 ToolLLaMA,其工具调用能力达到与 ChatGPT 相当的水平。

评论

登录后评论