☰
大模型预训练数据选择:OPUS的高效原则与落地实践
2026/10/24 2:58:37 网站建设 项目流程

做预训练的人大多都承认一件事:模型的下限看算力和架构,上限看数据。可“数据”恰恰是整个流程里最说不清的部分。最近我认真跟了一份题为 OPUS 的工作,它的副标题把目标讲得很清楚:在大模型预训练的数据选择上,追求一种既高效又有原则(efficient and principled)的做法,而且适用范围要广——标题最后那个 in Every 虽然被截断了,但结合这几年的研究脉络,基本可以判断它想覆盖的是每一个训练阶段、每一种数据规模、每一类数据领域。这篇博文想以一个普通训练者的视角,聊聊 OPUS 这类“有原则的数据选择”到底在解决什么问题、怎么把它装进自己的训练管线,以及我实际踩过哪些坑。

1. 预训练数据筛选:为什么它成了大模型工程的“隐藏主战场”

1.1 数据多不等于数据好

先泼一盆冷水:单纯堆数据,早就不是最优策略了。早年的做法是能抓多少抓多少,抓完洗干净就往模型里灌,大家比拼的是“谁能把清洗流水线做快”。但等到语料规模到了万亿 token 量级,问题就变了——你不再缺数据,你缺的是“值得让模型花算力去学”的数据。

我自己的习惯是先对语料做一次“体检”。把一批原始爬取文本按段落切好,采样几万条人工过一遍,你会发现一个很残酷的事实:真正信息密度高、表达规范的优质文本,可能连三分之一都不到。剩下的大头是什么?是重复的新闻稿、凑字数的营销文、机器翻译腔、框架雷同的常识科普,还有大量“看着通顺但毫无新意”的注水文。如果这些数据按原始比例进入训练,模型会被迫把大量容量花在记忆噪音上,表现为训练 loss 掉得慢、下游任务表现配不上它的参数量。

这时候自然会想到一个动作:筛选。可筛选的坑在于,你用什么标准筛?长度、符号比例、语言模型困惑度、分类器打分,这些手段各有各的道理,也各有各的死穴。到底哪个标准是“有原则的”,恰恰是 OPUS 这类工作想回答的问题。

1.2 传统筛选手段的三个天花板

我把常见做法列成一张表,方便对照:

手段原理优点天花板
n-gram / MinHash 去重去掉完全或近似重复的文本便宜、可扩展到超大规模只能解决冗余,不能判断“是否值得学”
规则过滤按长度、标点比例、语言占比过滤极快、稳定过滤掉的是“明显异常”,不是“低价值”
质量分类器用一个分类模型给文本打质量分能捕捉一些语义层面的好坏分类器的训练标签本身带偏见,跨领域会失灵
困惑度打分用语言模型对文本算困惑度能反映文本“是否像自然语言”高困惑度不等于低质量,专业文本天然困惑度高

这条表想说明一个核心问题:传统手段解决的是“异常文本”问题,而不是“有用文本”问题。去重能让模型不再重复记忆同一篇文章,规则能挡住乱码,但没有任何一个规则能告诉你:在剩余的一千亿 token 里,应该让模型先学哪些、后学哪些、每种各学多少。

困惑度是最容易被误解的一个指标。我刚做数据筛选时也犯过错:把困惑度高的文本一律当成噪音滤掉,结果发现代码和数学语料大比例被误杀——因为这些领域文本的困惑度天然就比新闻和百科要高。后来才明白,困惑度衡量的是“模型觉得这段话难不难”,而不是“这段话值不值得学”。困难与价值,是两回事。

1.3 数据选择的本质是一个带约束的优化问题

跳出具体工具,把“数据选择”这件事数学化一点看:你有海量候选文档,每个文档都有自己的内容特征、难度、与其它文档的重合度;你的训练预算有限,可能是“总共只训 X token”,也可能是“最多用 Y 个 GPU 时”。问题是:在这些约束下,选择哪部分数据、给每部分多少权重,能让模型的最终能力最大化?

这个问题天然是组合优化——从 N 个文档里挑出一个子集或一种混合权重,N 一旦上亿,暴力搜索完全不可能。所以任何可用的方法都必须做近似,而“有原则”的意思,就是你得先定义清楚“最大化的是什么”。

OPUS 的标题里用 principled 而不是 heuristic,这其实是刻意在跟一堆老做法划清界限。规则筛选是启发式:它有效,但你无法严谨说明它为什么有效、什么时候失效。而一个有原则的方法,会先把目标函数写出来,再在目标函数下做决策。哪怕这个目标函数是简化过的,至少你随时能回答“它在优化什么”。

这是我认为数据选择这几年最重要的一个思想转变:从“筛选脏数据”转向“在一个明确的效用函数下分配训练预算”。

2. OPUS 的解题思路:把“感觉”变成“目标函数”

2.1 “有原则”的第一步:目标函数可写、可算、可解释

OPUS 这类方法落地的时候,目标函数大概会长这样:对每个候选数据块定义一个“学习效用”,它通常是三个项的加权组合——代表性(这个块代表了多少同类型数据)、新颖性(它提供了多少已有数据没有的信息)、以及难度适配度(它的难度是否匹配当前训练阶段)。

代表性好理解:互联网上同一个话题可能有几十万篇文章,任意一篇单独看都不差,但你只需要其中几百篇就能覆盖这个话题的基本知识。新颖性则要求你考虑“重复”,但不是字面重复,而是语义层面的重叠。难度适配度是最微妙的一项:训练初期模型还在学语法和常识,喂太高难度的数学证明只会拖慢收敛;到了训练后期,如果一直喂简单文本,模型又学不到新东西。这其实就是课程学习的思路,但 OPUS 这类方法希望把它变成优化问题里的一个显式约束,而不是拍脑袋定一个难度曲线。

2.2 “高效”从哪里来:代理信号 + 采样打分 + 在线更新

如果老老实实拿训练主模型给全量语料打分,成本是灾难级的。打一万亿 token 的分数,等于多做一次全量前向传播,甚至比训练本身还贵。所以高效的关键在于三个字:别全算。

第一层省算力的手段是代理信号。不追求每个文档都用大模型精算,而是用一堆轻量特征做粗排:文本哈希嵌入、n-gram 重合度、向量聚类、小模型的困惑度等。这些信号互相之间相关性不高,组合起来已经能区分“优质语料”和“注水语料”的大致分布。

第二层手段是采样。你不需要给每个文档打分,只要从不同簇里抽出足够多的样本,把簇级别的分数估计出来,再假设簇内文档同质,就能把打分成本再降一个数量级。

第三层是动态更新。训练过程中模型在变,最优数据分布也在变,所以没必要一次性把分数定死,定期用探针模型重算一批关键样本的分数,做在线修正即可。

这三层叠起来,就是我在实际工程里理解的 OPUS 式效率来源:不是某个单一魔法,而是“粗排 + 采样 + 在线更新”的组合拳。

2.3 “in Every”的野心:阶段、领域、规模都要能套

标题最后落在一个没写完整的 Every 上。按现在的整体研究趋势,我猜测它想覆盖三个维度。

第一个维度是训练阶段。预训练不是铁板一块,早期、中期、晚期的最优数据配方是不同的,一套静态筛好的语料没法同时在三个阶段都是最优。第二个维度是数据领域。代码、数学、百科、对话、多语言,不同领域的“质量”标准完全不同——你用同一个分类器给所有领域打分,必然在某个领域上失灵,所以选择方法必须能感知领域。第三个维度是模型规模。在 1B 模型上验证过的数据选择方案,能不能迁移到 100B 的规模上?如果方法本身有明确的目标函数,它在不同规模下应该都能工作,只是最优参数要重调。这也是“有原则”方法相对规则方法的另一个优势:规则通常没法解释自己为什么能跨规模,而有目标函数的方法可以。

当然,“每个维度都适用”是很高的要求,实际做下来总会打折。我更愿意把它理解成一个设计目标,而不是一个已经证明的结论。后面我会专门聊哪些场景下这套东西会失效。

3. 落地步骤:从“一堆乱糟糟的语料”到“训练器里的采样权重”

光聊理念没用,我把自己实际搭过的一条“OPUS 式”数据选择管线摊开讲。这套东西不依赖任何特定框架,思路可以直接搬。

3.1 先把语料切成“选择单元”

第一步不是打分,而是定义“一个数据单元”是什么。以行为单位太小,以整本书或整个网页为单位又太大——一个网页里前半段是教程后半段是广告,你没法精准取舍。

我用的单元是“语义段落块”:按标题结构和长度把文档切成 200-500 token 的块,然后做粗去重,把 n-gram 重合度超过 0.8 的块合并掉。这一步决定了后面所有打分的粒度。块太小,特征统计噪声大;块太大,选择粒度粗,容易整块保留垃圾内容。200-500 token 是一个在我试过的中文、英文、代码混合语料上表现都不错的区间。

3.2 搭一个轻量打分管线

我给每个块算四类特征:

  1. 文本统计特征:长度、标点密度、数字与符号占比、句均长度、词频分布的熵。
  2. 语义聚类特征:把块用小模型编码成向量,做粗聚类,给每个块一个簇 ID 和离簇中心的距离。离中心越远,通常是越偏门的样本——偏门不等于差,但在代表性维度上要扣分。
  3. 探针模型困惑度:用一个 1-2B 的探针模型算困惑度,注意要按领域分别统计,不要把代码和百科混在一起比。
  4. 与已知优质语料的相似度:维护一个很小的人工精选种子集(几千条即可),算每个块与种子集的最相似度——这一步是给“质量”兜底,避免聚类和困惑度把真正的好文本误杀。

然后定义一个打分公式,比如:效用 = α × 新颖性 + β × 代表性 + γ × 难度匹配 - λ × 冗余度。具体系数在不同数据池上要重新标定,但初始值可以设为 α=0.4、β=0.3、γ=0.2、λ=0.1,然后再手动抽查几百条看排名是否合理。

3.3 训练过程中做在线权重更新

静态打一次分就完事,效果会随时间衰减。我的做法是每训 5000 步更新一次权重,更新逻辑并不复杂:

def update_pool_weights(pool, probe_model, cached_scores, sample_ratio=0.02, alpha=0.85, temperature=2.0): # 1. 从池子里采样一个子集 sampled = pool.sample(sample_ratio) # 2. 用探针模型重算这批样本的效用 fresh_scores = probe_model.score(sampled) # 3. 平滑更新,避免单次噪声导致权重剧变 for doc_id, score in fresh_scores.items(): old = cached_scores.get(doc_id, score) cached_scores[doc_id] = alpha * old + (1 - alpha) * score # 4. 转换为采样权重 logits = torch.tensor([cached_scores[d] for d in pool.ids]) weights = torch.softmax(logits / temperature, dim=0) return weights

这段代码的核心是两件事:平滑(alpha 参数)和温度(temperature 参数)。平滑是为了抵抗分数漂移带来的抖动,温度则是控制选择强度——温度越低,权重越集中在高分样本,探索性越差;温度越高,分布越均匀,相当于退化回随机采样。

3.4 与训练框架的对接细节

权重算出来后,要接到数据加载器上。我的经验是:不要改训练代码,只在采样逻辑里做文章。训练端每来一个 batch,就从权重分布里抽一批块,然后正常拼接、掩码、训练。还要注意保持随机种子和 shuffle 的确定性,否则换一次权重分布,整个训练的可复现性就没了。

另一个容易忽略的点是分数缓存 checkpoint。每次更新完权重,把 cached_scores 存一份快照。否则训练中途崩溃,重启后分数全部丢失,整个更新过程要从头再来。这个我踩过不止一次,后面细说。

4. 选型对比与参数经验:三条路线,三种代价

数据选择不是只有“完全在线”一种玩法。我实际比较过三条路线,各有适合的场景。

4.1 三条路线的对比

路线做法成本稳定性适合场景
A. 离线静态过滤训练前一次性打分,保留 top k%最低高预算紧、只想快速提升数据质量基线
B. 迭代重加权每若干步重算一轮权重中中高大部分常规预训练任务
C. 在线自适应选择每步根据训练反馈动态调整高需调参追求极致效果、愿意承担工程复杂度

我自己的建议是:第一次做数据选择,先走 A 路线,把打分管线跑通、把评测指标搭好;确认收益后升级到 B;C 路线除非团队有专门的系统工程人力,否则不建议一上来就上。

4.2 关键超参的合理起点

几个我反复调过的参数,给一个“可用起点”:

  • 采样比例:每次更新重打分的比例,0.01-0.05 都行,再高收益就边际递减了。
  • 平滑系数 alpha:0.7-0.9。太小权重波动大,太大更新等于没更新。
  • 温度 temperature:1.0-3.0。初期用 3.0 多探索,后期降到 1.0-1.5 收束。
  • 更新频率:5000-20000 步之间。太频繁成本高,太稀疏则跟不上模型变化。

判断这些参数是否合适,最直接的方法是盯着训练 loss 和一小撮固定评测集:如果更新权重后 loss 出现明显震荡,说明温度太低或平滑不够;如果连续几轮评测集分数没变化,说明采样比例或更新频率太低。

4.3 我实际踩过的四个坑

第一个坑是分数漂移。探针模型训着训着就变强了,同一篇文档的困惑度全程在变,如果不做平滑,权重会跟着剧烈震荡,训练 loss 出现奇怪的台阶。解决办法就是上面代码里的 alpha 平滑,以及每次更新时重新归一化分数分布。

第二个坑是“死语料”问题。有些小众领域的分数始终不高,权重越来越低,最后几乎永远采不到,模型对这些领域彻底失明。这是纯贪心的结果——你在优化平均效用,代价是多样性塌缩。我的修法是加一个保底权重:给每个领域设置最小采样概率(比如总概率的 2%),保证再冷门的领域也有数据进入训练。

第三个坑是评估集污染。如果你把下游评测任务里的样本混进数据池,或者用评测集来做打分的种子集,模型的评测分数会虚高,但真实能力没涨。这个坑最阴险,因为它会让全组人对“数据选择有效”这件事产生错误信心。

第四个坑是探针模型与主模型的偏好不一致。1B 探针觉得好的数据,100B 主模型未必觉得好。我的经验是,探针模型的选择结果可以作为粗筛,最后 10% 的甜点区最好用主模型在小样本上验证过后再定。

5. 怎么证明这套选择真的有用:评测协议与成本账

数据选择项目最容易被挑战的问题就是:你怎么证明不是玄学?我总结了一套相对靠谱的验证流程。

5.1 评测协议别偷懒

每次做数据选择对比实验,我都会固定三组基线:随机采样、规则过滤、OPUS 式选择。训练预算完全相同,只允许数据分布不同。评测至少覆盖三类:一是分领域的留出集困惑度(领域要尽量分散,至少包括通用文本、代码、数学、多语言);二是若干公开下游任务;三是一小撮人工标注的“优质内容”上模型续写质量的盲评。

一个容易犯的错是只看总困惑度。总困惑度下降可能只是因为模型把重心挪到了某个大领域,其它领域其实退步了,平均之后看不出来。分领域困惑度曲线才能暴露这种问题。

5.2 小规模代理实验的价值

跑全量预训练做对比太贵,必须先做小规模代理实验。我在实践里常用的是 1B 参数、50B token 量级的实验——这个规模一两天能跑完,结论往大模型迁移时方向一致性还可以。

但有个前提:迁移前必须检查“选择方法的行为在规模变大后是否改变”。比如,如果某个方法在小模型上靠“增加高分数据重复度”获胜,到大模型上这种行为往往不再有效,甚至会起反作用,因为大模型对重复数据的记忆能力完全不同。我见过不止一次在小实验上效果显著、放大后效果消失的案例。

5.3 数据选择的账要这么算

最后是成本收益。我给一组实际发生过的大致数字做参考:一个万亿 token 的训练预算约为 1.5 万 GPU 时。单用规则过滤,几乎不花额外代价,但数据质量提升有限;如果给全量语料跑一个 7B 模型的困惑度打分,需要额外几千 GPU 时,前期成本很高;而 OPUS 式的代理打分加采样,前期成本可以压在几百 GPU 时以内,省下的钱换来的训练质量提升通常能覆盖掉这部分开销。

这个账的重点不是具体数字,而是思路:数据选择的成本要看“相对训练总预算的比例”,而不是绝对数字。只要前期打分成本控制在训练预算的 5% 以内,即使只带来 2%-3% 的综合评测提升,长期看都是划算的。

6. 对“Every”的冷思考:哪几类场景我不建议迷信数据选择

前面把数据选择吹了一通,但说实话,它并不是所有场景的银弹。有几种情况我觉得先用朴素方法反而更稳。

6.1 数据池太干净或太少时,选择空间有限

如果语料是人工梳理过的高质量数据集(比如几万本精选书、几百 GB 的专家创作内容),再去选择的价值就很低了,因为候选集本身没有太多“低质量冗余”可以挤掉。这时候更应该把精力花在配比调整和课程顺序上。

6.2 多模态与代码执行类数据,文本选择逻辑不完全适用

图像、音视频数据的“质量”评价逻辑和文本完全不同,一个文本效用函数搬到多模态上就是硬套。代码数据也有特殊性:代码的价值很大程度由“能否执行、能否通过测试”决定,这需要执行环境反馈,不是离线打分能覆盖的。所以 OPUS 这类文本侧方法,最稳的应用场景还是纯文本预训练。

6.3 别为了数据选择牺牲与对齐的衔接

预训练只是整个大模型生命周期的第一环。我调过不少 case:预训练阶段把某个领域权重压得很低,模型在该领域的通用能力确实省下来了,但后续做指令微调和对齐时,这个领域的数据又找不回来了——因为底座模型在这个领域的表示已经很弱。所以数据选择的目标函数里,最好显式加入一个“未来任务保留度”的项,或者至少在决策时留出安全边际。

最后分享一个我自己的体会:数据选择入门最大的障碍不是算法,而是心态。你会忍不住想加更多特征、调更复杂的模型、追求更漂亮的曲线,但真正起作用的往往是最朴素的几个信号,加上一套严格、可复现的评测。我建议任何人第一次做数据选择,都从 20% 的算力投入去搭评测、80% 的投入做管线开始,这个比例不要搞反。等评测能稳定区分基线和方法时,再回头优化打分模型,你会发现自己其实已经领先大多数团队了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询