Lecture 14:数据处理与数据混合
Stanford CS336 Language Modeling from Scratch | Spring 2026 | Lecture 14: Data,时长 01:24:46。
数据转换:从 HTML/PDF 到纯文本#
语言模型的训练数据并非天然以文本形式存在。即便已经完成了爬取,原始数据仍然是 HTML、PDF 或 GitHub 目录等结构化/半结构化格式,需要经过一系列**转换(transformation)**才能变成可供模型消费的 token 序列。
HTML 到文本:基于规则的提取#
互联网的绝大部分内容以 HTML 承载,因此 HTML→文本的转换是数据管线中最核心的环节。这个过程本质上是有损的:HTML 至少具有层次化语义结构(标签嵌套)或视觉布局信息(渲染后的空间关系),而输出则是线性的 token 序列。
转换过程中需要处理几个关键问题:
- 去除样板内容(boilerplate removal):导航栏、广告、页脚、菜单等非正文内容需要被剥离,只保留页面的主体内容。但”什么算正文”本身就是模糊的——有时导航元素本身也携带有用信息(比如帮助模型理解网页的结构)。
- 表格处理:简单表格可以用 Markdown 格式渲染,但嵌套表格(nested tables)的处理极具挑战性,某些时刻不得不做近似或放弃。
- 图片和多媒体:文本提取通常直接丢弃图片,这是信息损失的另一个来源。
实践中,HTML→文本的转换几乎全部采用基于规则的处理器,原因有两个:速度极快(需要跑在整个互联网规模的数据上),以及这个任务本身不需要太多”智能”。常用工具包括 Resiliparse 和 Trafilatura,在 DCLM 扩展评估集上,Resiliparse 的效果优于其他工具。不过,基于规则的方法不可避免地存在一定的错误率,因此数据中总会残留一些提取瑕疵。
未来可能出现基于模型的转换方法,但前提是模型必须足够快,且确实能带来比规则方法更高的准确率。
PDF 到文本:高价值但高成本#
Hugging Face 发布的 FinePDFs 数据集专门处理 PDF 文件。PDF 在互联网上的占比很小,但单位价值显著更高——如果有人专门制作了一份 PDF 文档,其内容质量大概率优于普通网页。
PDF 处理面临独特的挑战:
- Common Crawl 中的 PDF 文件往往是截断的(因为 PDF 文件体积大,爬虫有大小限制),需要重新爬取完整版本。
- PDF 本身可能是扫描件(本质上是图片),需要 OCR 或 VLM 才能提取文字,成本远高于 HTML 处理。
- 与 HTML 不同,PDF 的设计哲学是面向布局而非语义。HTML 有
<h1>、<p>等标签提供语义层级,PDF 则完全关注视觉排版,语义结构的恢复更加困难。
转换完成后,数据终于变成了文本形式——但距离可用于训练还差得很远。接下来需要经历过滤、去重和混合等一系列处理步骤。
数据过滤:定义质量并训练分类器#
经过转换得到的文本数据量巨大(可达数十万亿 token),但其中充斥着垃圾内容、重复模板和低质量文本。**过滤(filtering)**的目标是从海量原始数据中筛选出与目标质量标准匹配的子集。
通用框架:Target + Raw → Subset#
几乎所有过滤方法都可以归结为同一个骨架:给定一小批高质量的目标数据 T(target)和大量原始数据 R(raw),找到 R 的一个子集 T’,使得 T’ 与 T 在某种意义上”相似”。过滤算法需要满足两个核心要求:
- 泛化性:不能只返回与 T 完全相同的文档,而要能识别出 T 没有覆盖但质量相当的新内容。
- 极致速度:必须能够在整个互联网规模(可能达 100 万亿 token)上高效运行。
过滤的典型结果是将数据规模压缩到原始量的个位数百分比。
两类评分模型#
在 Target + Raw 框架下,具体的评分函数分为两大类:
生成式模型(Generative)——典型代表是 KenLM。在目标数据 T 上训练一个 n-gram 语言模型(通常是 5-gram),以 pT(x) 作为评分函数。对于原始数据中的每个文档 x,如果 T 的语言模型认为 x 的困惑度(perplexity)较低,则说明 x 与 T 风格相似,可以保留。
判别式分类器(Discriminative)——更为常见。将 T 中的样本作为正例、R 中随机采样的样本作为负例,训练一个二分类器。评分函数为 p(T∣x),即分类器判定 x 属于高质量数据的概率。工具方面几乎所有人都使用 fastText,因为它本质上是一个 bag-of-words 线性分类器,训练和推断速度极快。
训练完成后,对 R 中的每个文档计算分数,设定一个阈值,保留分数高于阈值的样本。有时保留操作是随机的(stochastic)——分数越高保留概率越大,而非硬截断。
模型过滤 vs 无模型过滤#
历史上,一些数据集(如 C4、Gopher、RefinedWeb、FineWeb、Dolma)刻意不使用基于模型的过滤,担心引入过多偏置。但目前的趋势是几乎所有人都在使用某种程度的模型过滤:除非算力极其充裕(可以直接在全量数据上训练),否则在有限算力下,智能过滤是避免将 FLOPs 浪费在低质量内容上的必要手段。
过滤实例#
语言识别(Language ID)——最基本的过滤之一。Meta 训练了一套支持 176 种语言的 fastText 语言识别模型,训练数据来自 Wikipedia 的多语言页面、Tatoeba 翻译网站等。语言识别本身是一个相对简单的任务,虽然存在 code-switching 和方言等边界情况,但它并不是训练好模型的瓶颈。例如 Dolma 直接保留 p(English)≥0.5 的页面。
领域定向过滤——以 OpenMathText 为例。如果目标是训练一个擅长数学的模型,可以专门构建数学数据集。OpenMathText(Paster+ 2023)采用了多级管线:先用规则过滤(是否包含 LaTeX 命令),再用 KenLM(在已知数学数据集 ProofPile 上训练,保留困惑度低于 15000 的文档),最后用 fastText 分类器判断是否为数学写作(阈值因是否包含 LaTeX 而异:包含 LaTeX 则门槛更低 0.17,不包含则更高 0.8)。最终得到 147 亿 token 的数学语料,训练出的 1.4B 模型在数学任务上优于使用 20 倍数据量但未经定向过滤训练的模型。
GPT-3 的过滤策略。正例来自 Wikipedia、WebText(Reddit 高星帖子的外链页面)和部分书籍;负例从一般网页中采样。训练线性分类器,按分数保留文档。LLaMA 的变体则使用 Wikipedia 引用的页面(而非 Wikipedia 文章本身)作为正例。
Phi-1 的 GPT-4 蒸馏过滤。从 The Stack 的 Python 子集出发,定义一个 prompt 让 GPT-4 判断代码的教育价值(“determine its educational value for a student whose goal is to learn basic coding concepts”),对 100K 样本做分类。GPT-4 标注为正例的样本作为 target T,然后训练一个更便宜的 random forest 分类器在全量数据上跑。结果:在 HumanEval 上,使用过滤数据训练的 1.3B 模型(36K 步达到 17.68%)优于使用原始数据训练的同等模型(96K 步仅 12.19%)。
毒性过滤。Jigsaw Toxic Comments 数据集来源于 Wikipedia 讨论页的人工标注,标记了哪些评论包含有毒内容。同样可以据此定义正负例,训练毒性分类器来过滤训练数据中的有害内容。
过滤阈值与训练 Token 数的权衡#
过滤分类器给出的分数存在一个阈值选择问题,而最优阈值并不存在一个普适答案——它取决于你打算训练多少 token。
核心直觉#
- 训练时间较短时(token 预算有限),应当使用高质量数据。高质量数据在训练初期的 loss 下降速度更快。
- 训练时间很长时(可以消费大量 token),可以容忍较低质量的数据。原因是高质量数据集通常较小,长时间训练意味着必须反复 epoch(重复训练同一批数据),最终会导致过拟合。
实验证据#
Michael Ryan 在一个 157M 参数模型上做了一组对照实验,使用 100 个 WARC 文件(Common Crawl 的极小子集)进行训练,观察不同过滤策略下 loss 随训练 token 数的变化关系。

几个关键观察:
- DCLM(高质量过滤)的 loss 起点较低、初期下降很快,但数据量小(约 97.6M token 即完成一个 epoch),多次 epoch 后 loss 下降趋缓,最终开始过拟合。
- Resiliparse(使用 Resiliparse 提取但未做模型过滤的数据,约 4.42B token)的 loss 起点很高,但因为数据量充足,可以持续训练而不 epoch,长期来看 loss 持续下降。值得注意的是,Resiliparse 作为 HTML→文本的提取工具在 DCLM 扩展评估上是效果最好的,但此处它代表的是”提取后不做质量过滤”的基线方案。
- 在训练初期(~1B token 以内),高质量过滤策略(DCLM、high_quality)明显优于低质量数据。但到 ~10B token 时,这些高质量数据集已经 epoch 了数十次,loss 反而不如使用低质量但充足数据的方案。
- 各曲线上的虚线竖线标记了每轮 epoch 的边界。高质量数据集的 epoch 密集(数据少),低质量数据集的 epoch 稀疏甚至不出现(数据多到训练一次都用不完)。
数据质量与数据数量之间存在根本性的张力。理想情况下希望两者兼得——既大量又高质量——但现实中高质量数据池总是有限的。因此过滤阈值必须根据训练预算来调整,而不能一刀切地追求”最高质量”。
过滤小结#
过滤是构建好模型的关键环节,尤其在算力受限(大多数人的现实处境)时。理论上,如果拥有无限算力,可以在全量数据上训练一个巨大模型而无需过滤,但现实中每个人都需要过滤。
过滤的基本配方是:确定什么是”好数据”的样子(找到现有的高质量数据集,或者用 LLM 做初步标注),然后训练一个轻量分类器将这个判断推广到全量数据上。
去重:精确去重与近似去重#
过滤之后得到了”高质量”数据集,但其中仍然充斥着大量重复内容。去重(deduplication)是数据管线中不可或缺的一步。
为什么要去重#
- 节省算力:重复数据不提供新信息,去掉重复项可以在不损失信息的前提下缩小数据集规模,使训练更高效。
- 防止记忆化:如果某段版权内容在数据中出现了大量副本,模型会倾向于逐字记住它,带来版权和隐私风险。
- 去污染(decontamination):需要确保测试集的内容不出现在训练集中,这在逻辑上与去重同构。
重复的来源#
互联网上的重复无处不在:
- 镜像站点:网站镜像(mirror)的存在就是为了复制内容,爬虫往往无法识别两个 URL 指向完全相同的内容。
- 代码 fork:GitHub 上 fork 一个仓库后,99% 的文件可能完全不变。
- 许可证/模板:MIT License 的文本在无数代码仓库中出现,页眉页脚模板在不同网站间高度重复。
- 近似重复:排版差异(一个版本有逗号、另一个没有)、实体替换模板(同一个广告模板,只是把”Canada”替换成了”USA”)。
- 极端案例:对 C4 数据集的审计发现,某个防毒面具的产品描述出现了 61,000 次。
去重的设计空间#
去重涉及三个维度的选择:
- 去重粒度:句子级、段落级、还是文档级?
- 匹配标准:精确匹配、存在公共子项、还是按公共子项的比例(近似匹配)?
- 处理策略:发现重复后,删除所有副本还是保留一个?
核心算法挑战#
去重本质上是一个比较操作:需要把每个 item 与其他所有 item 进行对比。而过滤是逐个判断单个 item 的质量——可以完美并行、线性时间。去重则面临 O(n2) 的朴素复杂度,在网络规模的数据上完全不可行。因此,去重文献大量依赖哈希函数来将问题降维到线性时间。这里使用的不是密码学哈希函数(如 SHA-256,追求碰撞抗性,用于区块链和密码学),而是更快速的通用哈希函数(如用于哈希表的那类),碰撞在此场景下不是灾难,反而是我们利用的对象。
精确去重#
精确去重在概念上很简单:对每个文档计算哈希值,哈希值相同的就是重复项,保留其中一个。实现上可以按 map-reduce 风格组织以便并行化。
C4(T5 论文中处理 Common Crawl 的方式)对精确去重的实现是:将每个文档切分为三句话的滑动窗口,对每个三句话片段做精确匹配。如果两个文档共享了同一个三句话片段,则从其中一个文档中删除这三句话。这个做法有点奇怪——它会破坏文档的连贯性(从中间挖掉三句话),但在实践中被采用了。
精确去重虽然清晰明确,但对于杂乱的网络数据来说不够用,因为真实世界中大量重复是近似重复而非完全相同。
MinHash:用哈希碰撞逼近 Jaccard 相似度#
为了高效处理近似去重,首先需要定义”近似匹配”的度量。Jaccard 相似度是标准选择:对两个集合 A 和 B,
J(A,B)=∣A∪B∣∣A∩B∣
取值在 [0,1] 之间,0 表示完全不相交,1 表示完全相同。例如 A={1,2,3,4},B={1,2,3,5},则交集为 {1,2,3},并集为 {1,2,3,4,5},J(A,B)=3/5=0.6。
在去重场景下,两个文档被视为近似重复当且仅当它们的 Jaccard 相似度超过某个阈值(如 0.99)。问题变成:如何在线性时间内找到所有相似度超过阈值的文档对?
MinHash 的定义#
MinHash 是一种随机哈希函数,其核心性质是:
Pr[h(A)=h(B)]=J(A,B)
即两个集合的 MinHash 碰撞概率恰好等于它们的 Jaccard 相似度。具体操作非常简单:
1def minhash(S: set[str], seed: int):2 return min(mmh3.hash(x, seed) for x in S)对集合中的每个元素用同一个哈希函数映射,然后取最小值。
为什么 MinHash 有效:特征矩阵视角#
MinHash 的正确性可以通过**特征矩阵(characteristic matrix)**直观理解。对于 A={1,2,3,4} 和 B={1,2,3,5},特征矩阵为:
| item | A | B |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 1 |
| 4 | 1 | 0 |
| 5 | 0 | 1 |
随机哈希函数的作用等价于对行做随机排列,然后看哪一行先出现”1”。MinHash 的值就是排列后第一个”有值”的行。
如果随机排列把第 1 行放到最前面,则 min(A)=min(B)(都选中 item 1)——碰撞。第 2、3 行同理。但如果第 4 行排在最前面,则 A 选中 item 4 而 B 没有——不碰撞。第 5 行也类似。
全集 {1,2,3,4,5} 中有 5 个元素,其中 3 个({1,2,3})同时属于 A 和 B,所以碰撞概率为 3/5=J(A,B)。这正是 Jaccard 相似度的定义。
从 O(n2) 到线性#
MinHash 的关键优势是将集合间的相似度比较转化为哈希值比较。我们不需要对每对文档直接计算 Jaccard(需要遍历两个集合),而是预先为每个文档计算 MinHash 值,然后只需比较这些哈希值是否碰撞。这可以通过标准的哈希表在线性时间内完成。
用代码验证:生成 100 个不同种子的哈希函数,统计 A 和 B 的 MinHash 碰撞率,得到约 0.6,与理论值 J(A,B)=0.6 一致。
局部敏感哈希(LSH):锐化碰撞概率的相变#
单个 MinHash 函数的碰撞概率等于 Jaccard 相似度,但这太”随机”了——碰撞概率随相似度线性变化,无法可靠地区分”相似度 0.99”和”相似度 0.5”。我们真正需要的是一个阈值效应:相似度高于某个门槛时高概率碰撞,低于门槛时几乎不碰撞。
**局部敏感哈希(Locality Sensitive Hashing, LSH)**正是用来解决这个问题的经典算法框架。
Band-Row 结构#
LSH 的核心思路是使用 n 个独立的 MinHash 函数,将它们组织成 b 个band,每个 band 包含 r 个哈希函数(n=b×r)。例如 n=12 时可以分为 b=3 个 band,每个 band 有 r=4 个哈希函数:
1Band 1: h1, h2, h3, h42Band 2: h5, h6, h7, h83Band 3: h9, h10, h11, h12碰撞的判定规则采用 AND-OR 结构:
- AND(band 内部):一个 band”匹配”,要求该 band 中所有 r 个哈希函数都对 A 和 B 返回相同值。
- OR(band 之间):A 和 B 被判定为”碰撞”,只要存在某个 band 匹配即可。
碰撞概率的推导#
设 J(A,B)=s,则:
- 单个哈希函数碰撞的概率为 s。
- 一个 band(r 个独立哈希函数)全部匹配的概率为 sr。
- 一个 band 不匹配的概率为 1−sr。
- 所有 b 个 band 都不匹配的概率为 (1−sr)b。
- 最终碰撞概率为:
P(s)=1−(1−sr)b
1def get_prob_collision(sim, b, r):2 prob_match = sim ** r # 单个 band 匹配的概率3 prob_collision = 1 - (1 - prob_match) ** b # 某个 band 匹配的概率4 return prob_collisionS 形相变曲线#
P(s) 作为 s 的函数呈现出漂亮的 S 形曲线——这恰好是我们想要的相变行为:

以 b=10,r=10 为例,不同相似度对应的碰撞概率为:
| Jaccard | 碰撞概率 |
|---|---|
| 0.7 | 0.2491 |
| 0.75 | 0.4399 |
| 0.8 | 0.6789 |
| 0.85 | 0.8884 |
| 0.9 | 0.9863 |
| 0.95 | 0.9999 |
| 0.98 | 1.0000 |
参数 r 和 b 的效果#
两个参数分别控制 S 曲线的不同属性:
- 增大 r(每个 band 内的哈希函数数量):曲线变陡峭并向右平移。匹配变得更困难——需要所有 r 个哈希函数同时碰撞,低相似度的误匹配率大幅降低。
- 增大 b(band 数量):曲线向左平移。匹配变得更容易——更多 band 意味着更多碰撞机会。
通过调节 b 和 r,可以将相变点精确定位到任意目标阈值。相变发生在 s∗=(1/b)1/r 处,此时碰撞概率约为 0.64。低于 s∗ 的碰撞概率随 b×r 增大趋向于 0,高于 s∗ 的碰撞概率趋向于 1。
实际参数规模#
在实际的大规模去重工作中,参数设置远比教学示例大。例如某篇去重论文使用 b=20 个 band,每个 band r=450 个哈希函数,总共 9000 个 MinHash 函数。
去重的全局性#
值得强调的一点是:去重不能仅在单个数据源内部进行。实际训练数据由多个来源组成,而不同来源之间可能存在大量重复。因此跨数据源的全局去重是必要的,尽管实践中不是所有人都做到了这一点。
MinHash LSH 是去重场景下的标准方案,它将 MinHash(逼近 Jaccard)与 LSH 的 band-row 放大机制结合,在线性时间内实现了具有可控精度的近似去重。
数据混合:多源数据的权重分配#
经过转换、过滤、去重之后,我们得到了若干个干净的数据源——Common Crawl 的文本子集、代码仓库、PDF 论文、书籍、Wikipedia 等等。语言模型的训练需要将这些异构的数据源混合成一个统一的训练流。数据混合(data mixing)的核心问题是:如何确定每个数据源的采样权重?
朴素方案及其问题#
手动设定(vibes-based)——根据经验和直觉手动调整各源的权重。这在实践中比预想的更常见,即使在比较新的论文中,也常看到研究者用某种方法得到初始权重后再手动微调。
均匀采样——对所有数据源等权采样。简单但粗暴,忽略了不同源的质量差异。
按比例采样(proportional mixing)——采样概率正比于各源的 token 数量 p(s)∝num_tokens(s)。表面合理,但如果存在一个巨大的低质量数据源,它会占据大量的训练 token 配额。
直觉上应当对高质量源赋予更高权重。但这里有两个重要的约束。
训练时混合比例的实现方式#
在实际训练中,混合比例在 batch 级别实现:填充每个 batch 时,对其中的每个序列独立地从混合分布中采样其来源。通常每个序列完整地来自某一个数据源(不会在 token 级别做混合),而一个 batch 内会包含来自多个源的序列,以降低梯度估计的方差。
约束一:多样性#
不同数据源之间往往是不可比的——代码、文学作品、论文、网页各有价值,不能简单地说”论文比代码质量高”。如果目标是训练一个通用模型,就不能把所有权重都堆在单一类型的数据上。
约束二:Epoch 问题#
每个数据源的规模是有限的。如果给一个小规模的高质量源分配了过高的权重,训练过程中就必须反复遍历该源的数据(epoch),最终导致过拟合。
这个问题可以通过一个简单的计算说明。假设有两个数据源:低质量源 10 万亿 token,高质量源 100 亿 token。采用均匀混合(各 50%)训练 1 万亿 token:
- 低质量源的 epoch 数 = 10130.5×1012=0.05——仅使用了该源 5% 的数据,连一轮都没训完。
- 高质量源的 epoch 数 = 10100.5×1012=50——每个数据点被重复训练了 50 次!
50 次 epoch 最好的情况是浪费算力,最坏的情况是严重过拟合。关键教训是:定义数据混合比例时,必须同时考虑各源的大小,否则会在不知不觉中对小数据源做大量 epoch。
UniMax:带 Epoch 上限的均匀采样#
这个 epoch 问题在多语言模型训练中很早就被注意到了。之前有些工作的做法是对 proportional mixing 的权重取某个幂次 p(s)∝num_tokens(s)α(α∈[0,1])来拉平分布,但这仍然是 heuristic 的。
UniMax(Chung+ 2023)给出了一个更明确的方案,核心思路是对各源均匀采样但加上一个硬性 epoch 上限 C。具体约束为:
p(s)×train_tokens≤C×num_tokens(s)∀s
即每个源被采样的 token 总数不超过其实际大小的 C 倍。这相当于一个安全网——防止小数据源被过度使用。存在一个简单的算法可以在此约束下求解最优的采样分布。
Regression-Based Mixing:用代理模型优化混合比例#
手动设定或简单启发式都无法系统地回答”什么混合比例最好”这个问题。Regression-based mixing(RegMix, Liu+ 2024; OlmixBase, Chen+ 2026 等)提供了一个更原则性的框架。
四步流程#

-
训练一批小规模代理模型:选择一个小模型(如 300M 参数),对不同的数据混合比例各训练一次。例如有三个数据源(Hacker News、GitHub、PhilPapers),尝试 (9.5%,35.9%,54.6%)、(87.7%,12.0%,0.3%)、(24.4%,1.4%,74.2%) 等多组配比。
-
拟合回归模型:每组混合比例对应一个 loss 值(可以是困惑度或下游 eval 指标)。用这些数据点拟合一个回归模型 f(w)→loss,其中 w 是混合权重向量。回归模型的选择包括对数线性模型(log-linear)和梯度提升决策树(gradient boosted trees)等。
-
在回归曲面上优化:回归模型给出了一个从混合权重到 loss 的廉价映射。在这个映射上搜索使 loss 最小的混合比例——这比直接训练大模型要便宜得多。
-
用最优混合比例训练大模型:将优化得到的数据混合比例应用到目标规模的模型训练中。
关键设计决策#
- 混合比例的采样分布:需要一个分布来生成候选混合比例。通常使用 Dirichlet 分布或指数分布。
- 回归方法:对数线性模型通常效果不错。
- 目标指标:通常基于下游 eval,但必须非常小心过拟合。如果目标 eval 偏向代码(如大量 coding benchmarks),优化器会自然地大幅上调代码数据的权重——这不是什么深刻发现,只是在做加权拟合。如果再去测试诗歌生成的能力,就会发现性能崩塌。相比之下,均匀采样和按比例采样没有这个风险,因为它们不依赖下游 eval。
- 代理模型规模:通常是几千万到几亿参数。模型太小可能不够准确,模型太大则失去了”先用小模型探索”的意义。
两个信仰飞跃#
RegMix 方法依赖两个未经严格证明的假设:
假设一:回归模型在最优点附近仍然准确。 回归模型是在随机采样的混合比例上训练的,但优化时会推向极端区域——而这些区域可能缺乏训练数据的覆盖。换句话说,我们在用回归模型做外推,而外推的可靠性没有保证。
假设二:小规模的最优混合比例可以迁移到大规模。 从上一节关于过滤质量与 token 数权衡的讨论中已经知道,最优策略确实依赖于训练规模——长训练更偏好低质量但数量充足的数据。因此小模型上的最优混合比例理论上不等于大模型的最优值。但在开源社区目前工作的规模范围内,这种迁移似乎”基本成立或至少不会明显错误”。
模拟 Epoch(Simulate Epoching)#
小模型到大模型迁移中有一个具体的陷阱:如果小模型训练用 10B token、大模型训练用 1T token(100 倍),那么在小规模实验中,一个仅有 100 亿 token 的高质量源可以轻松完成一个 epoch,优化器会给它很高的权重(“Wikipedia 太好了!”)。但放大到 1T token 时,同样的权重意味着对 Wikipedia 做 50 次 epoch——灾难性的过拟合。
模拟 epoch 的思路是:让小规模实验”看到”与大规模相同的数据稀缺性。具体做法是按比例缩小各数据源的规模:如果大模型训练 1T token、小模型训练 10B token(1/100 的比例),那么小模型只能使用每个源 1/100 的数据。这样小模型在优化时就会发现”Wikipedia 虽然好,但只有 1 亿 token(缩小后),不能放太多权重”——模拟了大规模下的 epoch 约束。
OlMix 论文中也使用了类似的 epoch cap 策略作为替代方案。
混合粒度的细化:Domain × Quality 网格#
值得补充的一点是,数据混合不仅发生在”不同数据源”之间,也可以发生在单个数据源内部。例如对 Common Crawl 进行内部混合时,可以先用工具(如 AI2 的 Web Organizer)按主题域(domain)分组,再叠加质量过滤分层,形成一个 domain × quality 的二维网格。网格中的每个 cell 作为一个独立的 mixture component 参与权重优化。这种做法比直接把整个 Common Crawl 作为一个源要精细得多,能够在源内部实现差异化的采样策略。
数据混合小结#
数据混合的问题本质是在多个异构数据源之间分配训练预算。Regression-based mixing 提供了一个系统性的框架:用小模型实验估计 loss 曲面,在曲面上优化混合比例,再将结果迁移到大规模训练。但这个过程中必须谨慎处理 epoch 问题(通过 cap 或模拟 epoch),并且时刻警惕对下游 eval 的过拟合——你在优化什么,就小心别只优化了那个东西。
后训练数据:从 OpenThoughts 到 Agentic Coding#
前面讨论的转换、过滤、去重、混合主要针对预训练数据——任务无关的通用语料。后训练(post-training)阶段则需要构建任务导向的数据集,用于 SFT 和 RLHF/GRPO 等流程。
通用配方#
后训练数据的构建遵循一个通用模式:
- 定义环境和任务:确定任务的领域(如 GitHub 仓库、数学题库、代码竞赛题)。
- 收集 prompt:从人类来源(Stack Exchange、竞赛网站)或合成生成任务描述。
- 收集 response:用强模型(teacher)或人类标注者生成回答。
在开源社区中,绝大部分后训练数据是合成的——由强模型生成。人工标注虽然质量可能更高,但速度慢、成本高。在前沿实验室,则更多采用人机混合(hybrid human-AI)的方式。
OpenThoughts:推理数据集#
OpenThoughts 是 o1 发布后受推理热潮驱动的工作,目标是构建高质量的数学/科学/代码推理训练数据。最终产出 120 万条样本。
数据来源涵盖大量的人类来源(Stack Exchange、NumMath 等数学题库)和部分合成来源。值得关注的几个发现:
- 多次采样有用:对每个 prompt 生成 16 个 response,总样本量 120 万即对应约 7.5 万个独立 prompt。
- 更强的模型不一定是更好的 teacher:QwQ-32B(32B 参数的早期模型)作为 teacher 竟然优于 DeepSeek-R1(当时最强的开源模型之一)。
- 答案过滤没有帮助:基于正确性做过滤(只保留答对的 response)并未带来收益。
- 少量聚焦来源优于大量杂源:使用少数精选的数据源效果更好,而非试图覆盖所有来源。
SWE-Smith:合成软件工程任务#
SWE-Smith(Yang+ 2025)关注的是 agentic coding——不只是生成代码片段,而是完成完整的软件工程任务。其方法是:
- 从 128 个 GitHub 仓库出发
- 用 LM 自动创建可用的开发环境(安装依赖等)
- 自动生成任务(修改代码引入 bug,然后要求模型修复)
- 验证任务实例的可执行性
最终得到 5 万个合成任务实例。但这些任务是合成构造的(人为引入的 bug),与真实的 GitHub PR 场景存在差距。
SWE-Zero:无需执行反馈的 Agentic 数据#
SWE-Zero(Ludwig+ 2026)的核心观察是:与数学不同,software engineering 任务的环境依赖极其沉重——多数 GitHub 仓库连安装都会失败,更不用说搭建数千个 repo-specific Docker 镜像。但有趣的是,强模型已经能够在不执行代码的情况下解决大量 SWE 任务。以 SWE-bench 为例,一些模型在不允许执行的条件下仍能达到接近 70% 的准确率(允许执行时约 80%),说明这些模型已经内化了一定程度的代码语义理解。
基于这个观察,SWE-Zero 生成了 30 万条 agent 轨迹(trajectories),全部来自真实的 GitHub PR(而非合成任务),使用 OpenHands scaffold,并特意限制 agent 只能执行 sed、grep 等基本操作而不能运行 Python,以防止”agent hacking”(agent 忽略指令直接执行代码来获得答案)。然后从强 coding 模型蒸馏生成轨迹,过滤掉违反指令约束的样本。
在此基础上,SWE-Hero 进一步提供了 1.3 万条需要执行反馈的 agent 轨迹。训练流程是先在 SWE-Zero 的 30 万条无执行轨迹上 fine-tune,再在 SWE-Hero 的 1.3 万条有执行轨迹上继续训练。
最新进展:规模化#
ReBench 是另一个独立的工作,同样试图大规模收集 GitHub PR 任务——整体思路类似(获取仓库、安装环境、用 LM 生成 response),是这个方向的并行探索。
最近的工作将 SWE-Zero 的思路进一步扩展到 1200 万条 agent 轨迹,结合 ReBench 等来源的任务。由于 SWE-Zero 不需要执行反馈,扩展的边际成本很低。在 ReBench 的任务中,只有约 32,000 条需要执行环境,其余 120,000 条不需要执行——而 SWE-Zero 框架可以利用全部任务。这个数据集规模已经足够大,甚至可以在较小的模型上取得不错的效果。
后训练数据的趋势#
后训练数据集正在快速演进,整体趋势是:
- prompt 来源:从完全合成到半合成(真实环境 + 合成任务),再到完全真实(真实 GitHub PR)。
- response 生成:几乎全部来自强模型蒸馏,但 teacher 的选择并不总是”越大越好”。
- 代码环境:是最大的工程痛点。大量的过滤和工程细节都围绕着”如何让这些仓库跑起来”展开。
- 规模:数据集从数万迅速膨胀到数百万乃至上千万条轨迹。
部分内容可能已过时