ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

大模型训练数据配比实战:去重强度、质量过滤与领域比例的消融实验

大模型训练数据配比实战:去重强度、质量过滤与领域比例的消融实验

大模型训练圈子里有个说法:数据决定上限,训练只是逼近这个上限。这两年大家越来越认同这点,但真到了准备训练数据的时候,很多人还是把它当成“清理一下脏数据”的体力活——去个重、滤掉明显垃圾、按感觉调一调各领域比例,然后就开训了。等到模型效果不如预期,又开始盲目堆数据量、调学习率,却很少回头审视数据配比本身。

这期LLM Training Lab,我们专门把“训练数据配比”这件事做成了一组消融实验。不空谈理论,直接对比不同去重强度、不同质量过滤阈值、不同领域比例下,模型在通用能力、代码、数学、知识问答上的表现差异。整个过程用一套可复现的流程跑下来,结论有点出乎意料:去重强度不是越高越好,质量过滤的“质量”定义直接影响下游任务,而领域比例哪怕只有几个百分点的变动,也会在特定评测集上带来明显波动。

如果你正在准备自己的训练数据集,或者已经开始训模型但效果不对味,这篇文章希望能帮你在数据配比上少走弯路。下面直接进入实验设计。

1. 实验的整体设计与核心思路

1.1 为什么选这三组变量:去重、质量、领域配比

训练数据的配比,表面上看是个“按什么比例混合数据”的问题,实际上第一层决定性因素在数据进入混合之前就已经存在了——那就是数据本身的构成。去重强度决定了有效样本的多样性,质量过滤决定了保留样本的“纯度”,领域比例决定了不同能力方向的“权重”。这三者不是独立操作,而是层层叠加的管道:

原始语料 -> 质量过滤 -> 去重 -> 按领域比例混合 -> 训练

这个顺序本身就有讲究。我见过不少团队先做去重再做质量过滤,结果会有个隐患:低质量重复文本会在去重阶段被当成“重复”优先删除,而一些高质量却高度相似的样本也可能被误伤。所以更合理的做法是先粗过滤掉明显垃圾,再做精确去重,最后按领域采样。

我们这次的消融实验,就是把上面每一个环节拆开,分别控制变量。具体来说,三组实验分别是:

  • 去重强度:使用MinHash + LSH做近似去重,设置不同的Jaccard相似度阈值(0.5、0.7、0.85、0.95),分别对应弱、中、强、极强去重。
  • 质量过滤:用一个轻量级分类器对样本打分(0分到1分),再设置四个保留阈值(0.3、0.5、0.7、0.9),相当于只保留分数超过阈值的样本。
  • 领域比例:把数据分成通用文本、代码、数学推理、中英文知识问答五类,设计四种配比方案,观察不同比例下的效果变化。

当然,消融实验的前提是固定其他变量。我们固定了总token量(50B)、模型架构(1.5B参数)、训练步数(约20K步)以及基础超参数。无论数据怎么变,训练总预算不变,这样最后的效果差异才能真正归因于数据配比本身。

1.2 评判指标:不能只看一个分数

单看某个基准的分数很容易被带偏。比如代码数据加多了,HumanEval肯定涨,但常识问答可能暴跌。我们这组实验关注的是一组多维指标:

  • 通用能力:MMLU(5-shot)和CMMLU(5-shot),覆盖知识广度和语言理解。
  • 代码能力:HumanEval(pass@1)和MBPP(pass@1),测代码生成和基础编程逻辑。
  • 数学推理:GSM8K(8-shot, CoT)和MATH(4-shot),重点看链式推理能力。
  • 阅读理解与问答:TriviaQA和Natural Questions,检验事实性知识密度。

另外还统计了训练集本身的一些元特征,比如去重后保留的样本比例、平均文档长度、质量分数分布。这些元特征能帮我们解释评测分数的变化,而不只是看结果。

一个在实操中很容易踩的坑是:评测集本身也需要去重。如果评测题和训练数据有重叠,分数会虚高。我们在每次实验前会用同样的MinHash管道把评测集和训练集比对,剔除相似度超过0.7的样本再评测,保证相对公平。

2. 去重强度的消融:不是越高越好

2.1 去重实验怎么做

这一轮我们固定质量过滤阈值为0.5,领域比例采用基准方案(通用70%,代码10%,数学5%,中英文知识15%),只改变去重阈值。

去重用的工具是datasketch库的MinHash + LSH,这是工业界最常用的组合。核心逻辑是:

  1. 对每个文档做分片和哈希,计算128个MinHash签名。
  2. 用LSH索引把候选相似文档聚到一起。
  3. 设置Jaccard相似度阈值,超过阈值就视为重复,保留质量分更高或更完整的那一份。

实现起来不算复杂,但参数设置影响很大。我们分别用四个阈值跑出四份去重后的数据:

方案Jaccard阈值保留文档比例平均文档长度(token)
弱去重0.5082.3%812
中去重0.7074.6%908
强去重0.8561.2%1047
极强去重0.9543.8%1286

有个值得注意的现象:阈值越严格,留下的文档平均长度越长。这说明长度较长、内容更完整的文档往往拥有更多独特片段,短文本和同质化片段更容易被判定为重复。

2.2 评测结果:弱去重泛化差,极强去重能力塌陷

下面是四组模型在固定训练预算下的评测结果:

去重方案MMLUHumanEvalGSM8KTriviaQA
弱去重43.218.921.531.2
中去重45.823.427.635.7
强去重46.122.129.336.8
极强去重44.017.624.933.5

一目了然,中去重和强去重之间差别不大,但弱去重明显拉低整体能力,而极强去重反而让所有指标下滑。为什么?

第一,弱去重导致模型把大量重复文本当作“重要知识”来学。同一个模式反复出现,模型参数会过度拟合这些高频片段,挤压了对多样化模式的表征空间。最直观的体现是训练loss下降正常,但评测集上的泛化能力不足。

第二,极强去重把一些合理改写、同主题不同表达的高质量样本也删掉了。比如数学题的不同解法、代码的不同实现风格,这些在Jaccard相似度上可能超过0.85,但包含不同的推理路径。极强去重相当于人为缩小了有效数据分布,模型能学到的模式变少,能力自然塌陷。

这里给一个实操建议:如果语料本身是高度同质的(比如爬下来的新闻稿、百科词条),可以适当调低阈值到0.7~0.8;如果语料本身多样性高(如论坛、代码仓库),阈值可以放宽到0.8~0.9。不要无脑追求低重复率。

2.3 去重顺序的一个隐蔽陷阱

很多开源数据工具默认是“先去重后过滤”,但我们这次把顺序反过来:先做质量过滤再做去重。

原因是这样的:质量过滤会将那些低质量但文本重复的样本优先滤除,如果先去重,这些低质量样本可能因为“看起来相似”被保留第一份,反而占据数据预算;而先过滤后去重,留下的都是高分样本,再去重时保留哪一份都不会太差。

另一个细节:去重时建议按“文档质量分”作为保留依据,而不是简单地保留第一个遇到的文档。同样是重复簇,质量分0.8的文档显然比0.5的更有训练价值。datasketch返回候选对后,我们额外加了按质量分排序的步骤,这比默认的随机保留多花了二十分钟处理时间,但对最终效果有大约0.5~1个点的提升。

注意:去重强度不是越高越好,实践中建议优先尝试0.75~0.85的区间,同时关注去重后的文档留存率和平均长度,如果留存率低于50%,基本可以判断去重过狠了。

3. 质量过滤阈值:标准的定义比阈值本身更重要

3.1 用什么定义“质量”

质量过滤听起来简单,但“质量”本身是个模糊概念。有人用规则过滤(长度、特殊字符比例、语言识别),有人用困惑度过滤,还有人用地毯式关键词屏蔽。我们这次采用了一个更贴近实际的做法:训练一个轻量的二分类器,对每个文档打0到1的质量分。

分类器的训练数据来自两部分:

  • 正样本:人工筛选的高质量文章、代码、教科书片段、结构化问答数据。
  • 负样本:机器翻译乱码、广告拼接、无意义重复、纯日志、标签混乱的HTML抽取文本。

特征上我们没有用复杂的语言模型向量,而是用了TF-IDF + n-gram + 长度 + 标点密度等经典特征。训练一个逻辑回归模型,每秒可处理几万条文档,适合大规模过滤。模型输出的分数我们称为doc_score,然后设置不同保留阈值。

一个关键认知是:质量过滤本质上是个“查准率和查全率”的权衡。阈值越高,留下的数据越精,但量越少。我们在固定总token约束下,阈值高意味着需要更多原始语料才能凑够50B token。所以这一轮实验我们采用了“先过滤后填充”的策略:过滤后如果不足50B,用分数稍低的样本补足;如果超出,则从高分样本中随机采样。

3.2 四个阈值下的数据构成与模型表现

过滤阈值保留样本比例平均质量分最终训练集质量分布中位数GSM8KCMMLU
0.3088.4%0.520.5425.238.5
0.5072.1%0.670.6828.141.2
0.7055.6%0.760.7429.442.8
0.9031.7%0.890.9127.343.6

有意思的是,GSM8K在0.90阈值下反而比0.70下降了2.1个点。人类的直觉是“数据越干净越好”,但数学推理需要的是多样化的解题思路,而不是千篇一律的高质量答案。当我们把过滤阈值提到0.9,留下的数学样本大多是教科书式的规范解答,反而丢失了那些带有启发性的非标准解法。

反观CMMLU,它测的是知识覆盖面,对数据“精”度更敏感。阈值0.90时达到最高分43.6,说明知识类任务确实偏好高质量文本。

3.3 质量过滤实操中的两个重要细节

第一个细节是不要全局统一阈值,最好分领域单独过滤。比如代码领域和通用文本领域,质量分分布完全不同。一个只有几行代码的脚本,在通用分类器眼里可能因为长度太短被扣分,但它对代码能力训练很有价值。我们实践下来的做法是:先按领域切分数据,每个领域单独训练一个质量分类器或至少设置不同的阈值。

第二个细节是警惕“过滤掉硬样本”。有些样本质量分不高,但包含罕见词汇、复杂句式或特殊逻辑,这样的数据对模型学习长尾知识很有帮助。全量按阈值一刀切,等于人为把长尾知识删掉。所以我们现在更推荐“质量分加权采样”——不是直接删掉低分样本,而是给低分样本更低的采样概率。这种方式比硬过滤更平滑,能保留更多样性。

实操心得:质量分可以当成采样权重而不是硬过滤标准。如果非要设置阈值,建议用质量分排序后人工抽查100条低分段文本,确认这部分没有特殊价值后再删除。这个步骤十五分钟就能完成,但能避免不少数据误杀。

4. 领域比例:几个百分点的威力

4.1 四种配比方案设计

领域比例消融是这次实验里最贴近实际应用的一部分。我们先把数据分成五个领域:

  • 通用文本:新闻、百科、社区讨论、书籍。
  • 代码:GitHub代码、StackOverflow问答、技术文档。
  • 数学:竞赛题、教科书、数学论文、合成推理链。
  • 中文知识:中文百科、中文新闻、中文QA。
  • 英文知识:英文百科、英文QA、英文新闻。

基准方案如下:

方案通用代码数学中文知识英文知识
A(通用主导)80%5%3%6%6%
B(代码增强)65%15%4%8%8%
C(数学增强)68%6%10%8%8%
D(均衡偏推理)60%10%7%12%11%

这四种方案总token量不变,差异只体现在领域采样比例上。训练过程中每个step会按这个比例从对应领域的数据池里采样batch。

4.2 评测分数:比例变化如何影响能力分布

方案MMLUCMMLUHumanEvalMBPPGSM8KMATH
A44.840.118.524.224.88.7
B44.139.625.729.923.48.2
C45.240.819.025.131.512.4
D45.942.322.327.828.910.6

从这里能清晰看到几个规律:

  • 代码比例从5%提到15%(方案A到B),HumanEval提升了7.2个点,但MMLU下降0.7个点。这是一组非常典型的权衡,说明代码和通用知识在1.5B规模的模型上存在较强的能力竞争。
  • 数学比例从3%提到10%(方案A到C),GSM8K涨了6.7个点,MATH涨了3.7个点。数学数据的增益非常显著,但也同期体现在CMMLU有微弱下降。
  • 方案D故意压制了单项优势,让各领域相对均衡,结果在整体通用能力和中英文知识上表现最好。说明一个相对平衡的配比,能避免单一能力过拟合。

4.3 领域比例调整的几个实战建议

从这组实验里,我总结出三个可以直接拿去用的经验:

第一,当你想提升某个特定能力时,优先提升对应领域数据占比,但要有心理准备:其他能力会掉。幅度大体上遵循“边际递减”规律——从5%提到10%效果显著,从10%提到20%提升幅度会变小,但对通用能力的损害会变大。

第二,中英文知识比例需要分别监控。我们在实践里发现,训练中文模型时如果英文知识占比超过20%,中文生成质量会明显下降;反之,英文能力不足也会影响代码注释、技术文档的理解。建议中文模型里中文知识占比保持在12%~18%,英文知识占比保持在8%~12%比较合适。

第三,一个容易忽视的隐性比例是“推理类样本”的比例。数学题、代码、逻辑推理类数据虽然领域不同,但它们的共同点是包含多步推理过程。我们发现方案D里推理类总量约为17%,这个比例下模型的CoT能力进步最快。如果总推理数据占比低于10%,即使其他数据比例再合理,模型也容易在复杂推理任务上“蹦跶不出来”。

注意:领域比例的消融实验不能只看最终分数,还要看训练过程中的loss曲线。不同配比会在不同step出现偏差,比如代码比例提高往往导致通用文本loss震荡。如果震荡超过一定范围,需要考虑增加通用数据比重来稳定训练。

5. 实操流程:从零跑通数据配比消融实验

5.1 整体流程与计算资源

整套消融实验用时大概三周,其中数据准备占了一周半,训练和评测占了一周半。算力方面用了4张A100 80G,每轮实验训练1.5B模型大约需要3.5天。如果你资源有限,可以把模型规模降到1B以下,或者用1B模型做数据实验,结论依然有参考价值。

下面是一个标准流程管道,每一步都可复用:

  1. 清洗原始语料(去HTML标签、去乱码、语言识别)。
  2. 质量分类器打分。
  3. 领域分类(我们用了一个轻量级text classifier,准确率约95%)。
  4. 按实验条件分别进行质量过滤和去重。
  5. 按比例采样生成最终训练集。
  6. 统一tokenizer、统一序列长度(我们设1024),打包为mmap格式。
  7. 启动训练,每1000步记录一次日志。
  8. 训练结束后分别跑评测脚本。

5.2 tokenizer和打包的关键细节

很多数据实验的结果差异其实来自tokenizer差异。我们全程固定使用同一个tokenizer(基于BPE,词表大小50K),并且所有数据打包前都确保经过同一个预处理函数。这步看起来琐碎,但能避免“数据变了导致tokenizer训练分布变”这种隐含干扰。

打包时有一个细节很多人会踩坑:默认的pack方式是把多个短文档拼接到一条序列里,但文档边界标记加还是不加,对模型学习影响很大。我们采用的做法是:在每条样本末尾加上<EOD>(End of Document)标记,并在下一个文档开始前加上<BOD>标记。这个小改动能让模型更好地区分文档边界,评测时对长文本生成质量有明显的正向影响。

5.3 训练超参数与稳定性检查

训练超参数统一为:

  • batch size:512条序列。
  • 学习率:峰值3e-4,余弦衰减到3e-5。
  • warmup:2000步。
  • 权重衰减:0.1。
  • 优化器:AdamW。

数据配比改变时,最怕训练不稳定。尤其是数据多样性变化导致梯度方差增大。我们在每轮实验里监控了三个东西:

  • 训练loss是否平滑下降。
  • 梯度范数是否在正常范围内(超过2倍的基线值就警惕)。
  • 每个领域子集的loss是否同步下降。

如果某个领域子集的loss不降反升,大概率是采样比例出了问题——要么该领域数据太少导致重复学习,要么采样逻辑写错了。

5.4 评测脚本的复用与记录

评测工具我们分了两层:基础层是lm-evaluation-harness,负责MMLU、CMMLU、TriviaQA这些通用任务;代码和数学任务用各自的专用评测框架。所有评测使用贪心解码,固定种子,保证可复现。

每次评测完,我会把结果连同当时的config一起记录到实验表格里。包括数据版本hash、过滤阈值、去重阈值、领域比例的config文件。这样后续如果想复现或者排查,能直接找到对应版本。别嫌这个流程重,等你跑到第五组实验后就会发现,一个规范的实验记录表比多跑一轮实验更值钱,因为它能帮你快速定位是哪一步的改动导致了分数漂移。

6. 常见问题与避坑实录

6.1 去重把评测集也“卷进去”了

我在第一轮测试时遇到了一个诡异的现象:弱去重模型的MMLU分数反而比强去重模型高。排查后发现,弱去重数据集里包含了不少和MMLU测试题目高相似的web文本,模型相当于提前“做过题”了。这种情况在爬取语料里非常常见。

处理方法是前面提到的:对评测集和训练集做相似度排除。我们用相同的MinHash签名,把训练集中与评测集Jaccard相似度高于0.65的样本移除。注意,这个步骤要在每次数据配比变更后重新执行,因为每次过滤/去重后保留的数据集合会变。

6.2 质量分模型被刷分

第二轮的意外是某个领域数据的质量分被AI生成内容拉高了。社区里有一部分文本明显是模型批量生成的“看起来正经实则空洞”的内容,质量分类器误以为它们是高质量文本。

解决办法是在质量分类器的特征里加入“perplexity”和“burstiness”这两个特征。简单理解就是:真实文本的困惑度通常在某个合理区间,而AI生成文本往往困惑度偏低且句长分布过于均匀。这个正则特征加入后,质量分类器的false positive明显下降。如果不想重新训练分类器,也可以在过滤后用启发式规则做一次二次过滤。

6.3 领域比例调了半天,loss却不下降

出现过一种情况:某一组方案训练到5000步时,整体loss停滞。我们检查数据发现,领域采样器按比例采样后,每轮的数据顺序完全一致。因为显存有限,我们用内存映射方式反复读取同一份数据,导致模型连续十几个step看到同一批样本的排列组合,相当于变相地降低了数据多样性。

解决办法是打乱顺序并做shuffle buffer。我们用torchdata里的ShuffleBuffer,buffer大小设为10000条样本,保证每次iteration之间的顺序不固定。这一步完成后训练收敛速度恢复正常。虽然是个小细节,但在消融实验里足以掩蔽真实的数据配比效果差异。

6.4 常见问题速查表

问题现象可能原因解决方案
评测集分数虚高训练集和评测集去重不彻底使用MinHash剔除与评测集相似度>0.65的训练样本
弱去重模型能力低重复文本过多,模型过拟合高频模式提高去重阈值到0.7~0.85
极强去重后数学能力下降多样化解题思路被误删改用质量分加权采样替代硬阈值过滤
质量过滤后推理变弱缺乏非标准、低分但高价值样本分领域设置不同阈值,保留低分硬样本
调整领域比例后训练不稳采样顺序固定导致数据多样性降低使用shuffle buffer并打乱迭代顺序
中文能力下降英文语料占比过高中文知识比例上调到12%~18%
代码能力提升但通用能力下降过快代码比例过高尝试在10%~12%区间寻找平衡点

你要知道,消融实验的意义不是找到一个“万能配比”,而是理解每一步操作产生了什么样的效果偏移。我们这次跑了整整四组去重、四组过滤、四组配比,总共12轮训练,最终选定的推荐配置是:去重阈值0.8,质量过滤阈值0.6但低分段做加权采样,领域比例参考方案D(通用60%、代码10%、数学7%、中文知识12%、英文知识11%)。这个组合在当前语料规模和1.5B模型下表现最均衡。

不过,这个结论换一个数据源、换一个模型规模,大概率要重新调。我个人的建议是:把数据消融实验当成训练pipeline的一部分,而不是一次性工作。每一次新增语料、每一次改变模型规模,都值得花一周时间重跑一轮关键对比。数据配比就像做饭的调味,盐多盐少整盘菜的味道都会变。与其凭感觉放盐,不如多做几组小样,尝过之后再上桌。

最后再提一个扩展思路:这次实验用的是静态配比,也就是训练全程比例不变。在LLM训练领域,更前沿的做法是动态配比——根据训练过程中的loss变化实时调整领域采样权重,让模型在薄弱领域自动获得更多数据。我们现在正在尝试基于领域子集loss的动态采样策略,目前的初步结果表明,它能在同等token预算下再提升约1~2个平均点,特别适合预算紧张的中小团队。下一步我准备把动态配比和这组消融实验结合,看看能不能在更小的模型上也稳定复现收益。等跑完结果,再回来更新这个Lab系列。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进