1. 背景与动机:为什么数据配比值得一场消融实验
做LLM训练的人,经常把一个公式挂在嘴边:模型效果 = 模型架构 + 数据质量 + 训练方法。但真到了实操层面,大部分人的注意力都在模型架构和训练方法上,数据管线往往是"差不多就行"的心态。直到我在一次基地模型评测中,发现一个奇怪的现象——两个规模完全相同的模型,用相同词元的SFT数据去对齐,最终在代码生成和数学推理上的成绩能拉开近10个百分点。排查到最后,唯一变量就是预训练阶段的数据管线不同。
从那时起,我意识到一个被人忽视的事实:预训练数据的配比策略,本质上是一种超参数,而且在很多情况下,比学习率、batch size这些传统超参数对最终效果的影响更大。去重强度、质量过滤阈值、领域配比这三个旋钮,每一个都牵动着数百亿词元的命运,但我翻遍内部实验记录,发现针对这三者的系统研究几乎是空白。大多数团队还在靠直觉和经验做决定——代码数据多一点?去重狠一点?中文语料加倍?每个人都有一套说法,但没人说得清为什么。
所以就有了这个系列的第17期实验。我打算把这三个变量拆开,用控制变量的方式做一组完整的消融实验,搞清楚它们各自对模型效果的影响方向、影响幅度和交互关系。简单说,这就是LLM训练数据配比的"校准实验"——把默认配置的各个旋钮逐一拧一遍,看看从基线出发,每个方向拧一格到底会发生什么。
这篇文章会完整记录我的实验设计思路、数据管线搭建方案、12组消融配置的详细结果,以及我在这个过程中踩过的一堆坑。无论你是在训练自己的小规模基座模型,还是纯粹想理解大厂数据管线背后的决策逻辑,这篇都能给你一些可复用的参照。
2. 实验设计:三个变量、四类基准与12组配置
2.1 变量定义:去重强度、质量过滤与领域比例
先把我实验里的三个变量说清楚,免得后面看结果的时候犯迷糊。
去重强度指的是数据管线中N-gram近似去重(我选用的是MinHash算法)的操作严格程度。我不采用"去重/不去重"的二元设定,而是按去重后语料保留比例分为三档:宽松(保留80%)、中等(保留60%)、激进(保留40%)。保留比例越低,说明去重强度越高。之所以设置三档而不仅仅是"有/无",是因为真实生产环境中,去重强度从来不是开关,而是一个连续旋钮——你选的阈值和向量维度决定了你能保留下多少数据,而数据留下来多少,又直接影响最终的多样性。
质量过滤我采用的是三层过滤体系:规则过滤(按长度、重复率、特殊字符比例)、分类器过滤(用一个轻量级的text classifier打分,参考fastText的深度)和嵌入相似度过滤(去掉与已有主题聚簇距离过近的冗余样本)。实验时我把这套体系定义了一个综合分数,分三档设定:松过滤(只保留分数最低10%之外的,即过滤掉10%垃圾)、中过滤(过滤掉30%)、严过滤(过滤掉60%)。注意这里的过滤比例只是相对粗细,实际操作中每一档都对应一套明确可复现的参数。
领域比例就更好理解了——代码、数学、百科、书籍、论坛这五类语料在最终混合数据中的占比权重。我在基线配置上做了一组再配平处理,生成了三套比例方案:自然分布(保留原始爬取的天然比例)、强化代码与数学(将代码和数学类总占比从基线提了两倍)、均衡分布(五大类尽量拉平,把论坛等低质量源的配额压下去)。
2.2 基准测试设定与实验组矩阵
评测基准我选了四组,因为单个基准太容易被"过拟合"到某类数据上:
- 通用能力:MMLU + CMMLU,考察常识与多语言知识
- 代码能力:HumanEval + MBPP,考察代码生成与理解
- 数学推理:GSM8K(含中文翻译扩展集)+ MATH,考察数学解题和CoT能力
- 通用语言建模:C4验证集上的困惑度,作为监控指标而非唯一评判
实验矩阵按照"基线 → 单变量调整 → 双变量组合 → 最优候选"的漏斗方式排布,一共12组,每组用完全相同的模型架构(约7B参数)、完全相同的训练超参(固定学习率、固定batch size、固定总步数)和相同的训练数据总规模。这点非常关键——我的目标是观察配比本身的影响,所以总词元数必须锁死,不同数据配比生效的维度只能是各来源的占比和去重/过滤后的保留结构。
具体矩阵如下:
| 实验组 | 去重强度 | 质量过滤 | 领域比例 | 备注 |
|---|---|---|---|---|
| B0(基线) | 中 | 中 | 自然分布 | 对标团队默认方案 |
| T1 | 宽松 | 中 | 自然分布 | 只松去重 |
| T2 | 激进 | 中 | 自然分布 | 只紧去重 |
| T3 | 中 | 松 | 自然分布 | 只松过滤 |
| T4 | 中 | 严 | 自然分布 | 只严过滤 |
| T5 | 中 | 中 | 强化代码数学 | 只调比例 |
| T6 | 激进 | 严 | 自然分布 | 双变量联动:数据更强 |
| T7 | 宽松 | 中 | 强化代码数学 | 双变量联动:多样性+比例 |
| T8 | 中 | 严 | 强化代码数学 | 双变量联动:质量+立例 |
| T9 | 激进 | 中 | 均衡分布 | 双变量联动:去重+均衡 |
| T10 | 宽松 | 严 | 均衡分布 | 双变量联动:多样+均衡 |
| T11 | 激进 | 严 | 强化代码数学 | 三变量最优化候选 |
这一套下来,训练成本大约是12 × 1亿词元参数的预训练,在64张A100上跑了大概两周。说句实在话,烧卡烧得我肉疼,但拿到结果那一刻觉得值回票价。
3. 数据管线搭建:怎么把"配比"稳定落地成可复现的产物
3.1 管线架构与流程控制
设计实验矩阵的逻辑是一回事,真要把12组不同配比的数据稳定产出来,又是另一回事。我这个环节的核心要求是:除了目标变量不同,其余每个环节的操作必须完全一致。
管线的产出结构分四个环节:爬取/采集与清洗 → 质量打分与分级 → 去重处理 → 领域分类与配比混合。其中"质量打分与分级"和"领域分类"是在一个环节完成的,因为我的领域分类器就是按"质量标签+领域标签"做的双任务输出,这样处理的效率更高,也让两个标签之间的相关性可以被后面分析时利用。
去重和过滤的先后顺序值得单独提一下。开始我按"先过滤再去重"来做,后来发现一个尴尬的情况:质量过滤会把一些低分的长尾语料直接丢了,而这些语料如果先做MinHash去重,里面还有一部分是跟高分语料严重重复的——它们本身作为"另一份copy"存在,拉低了数据集的整体多样性。颠倒顺序后,先做去重、再做质量过滤,保留集的大小更稳定,查重基准也更干净。我最终采用的是"清洗 → 规则过滤 → 去重 → 分类与分数过滤"的顺序,实际上把规则过滤当做一个轻量保险丝,只滤掉纯垃圾,不承担质量分级职责。
管线里还有一个常被忽略但极其重要的环节:数据审计。每个阶段的输出都要统计token的分布、长度分布、重复率指标,因为只有当你知道数据在每一环被"杀掉"了多少,才能真正判断某个配置引起的下游指标变化是来自数据本身,还是来自数据量的收缩。我的管线在每个环节都做了快照审计,跑完一组就自动生成一份明细报告。
3.2 去重强度三档的具体实现:MinHash的阈值与近邻策略
去重用的是MinHash + LSH的方案,这个在业内已经很成熟了,但参数设定当中有不少细微的门道。核心参数有三个:shingle长度、MinHash签名长度、LSH阈值。我固定shingle为6(字符级,对中英文都适用),签名长度为128位,通过调节band和rows的组合来实现不同的去重阈值。
去重强度这三档,我是在LSH近邻搜索的阈值上拉开距离的:
- 宽松去重(保留率约80%):设定LSH中band=20,rows=6,近似阈值为0.7。这个档位下只有那些几乎一模一样的重复网页(转载、镜像、文本完全一致)会被抓出来,相当于只处理最明显的垃圾重复。
- 中等去重(保留率约60%):band=25,rows=5,近似阈值降到0.5左右。这个档位下,稍作改写、加了点前缀后缀的"半复制"内容也会被抓出来。
- 激进去重(保留率约40%):band=32,rows=4,近似阈值约0.35。这个档位实际上把大量主题相似、结构雷同的文本都判为重复杀掉,是真正意义上的多样性收缩。
这里有个重要的经验教训:MinHash的LSH阈值并不是精确控制,参数和结果之间的关系要靠实际数据校验。我跑完T1组做审计时,发现"保留率80%"这个目标跟实际结果有大约7个百分点的偏差,需要微调两轮才能把保留率压到指定区间。所以建议每一位做类似实验的同学,在参数设定之外务必做一个"标定循环"——用1%的样本预估保留率,再全量跑确认,否则你想做的三档就失真了。
3.3 质量过滤体系的分数校准
质量过滤这个环节,我遇到的最大问题不是模型选型,而是分数校准。初版过滤阈值设得挺随意,导致T4组(严过滤)跑出来后我检查数据,发现大量我主观认为"质量还行"的技术文档被误杀掉了。细查原因,发现是我的分类器在"技术型问答"和"垃圾广告"之间的区分度不够,很多技术论坛灌水帖被打了高分,而真正的官方文档因为格式规整反而像"机器人生成"被降了分。
解决方式也不复杂,就是做人工校准集。我花了大概三天的时间,标注了2000条各领域样本(从五个领域中各抽400条),按"可用/低质/垃圾"三分类标注,然后拿标注结果去重算每个分数段的精确率和召回率。经过两轮调参和阈值重设定,最终确定了三档过滤对应的归一化阈值。这里给一个可操作的建议:标注样本不需要多,但分布一定要跨领域均匀覆盖,否则你的过滤器会在某个不常被注意的领域上给你挖大坑。
质量过滤的三档设定:
- 松过滤:过滤综合得分最低的10%。主要只杀掉纯乱码、机器翻译糊成一片、URL和广告泛滥的极端数据。
- 中过滤:过滤掉最低30%。额外加一层:"重复性高但主题不聚焦"的内容,比如新闻聚合网站自动生成的那种整篇都是前几段拼接、"口水话段落占比高"的文本。
- 严过滤:过滤掉最低60%。这个档位会把大量"中等偏下水平"的社区讨论内容和短评也杀掉,留下来的语料整体风格会偏"教科书感",长度分布也会显著右移。
档位从松到严,最直接的代价是数据量的收缩,而更深层的代价是风格多样性的损失——这一点在后面的结果里会体现得非常明显。
4. 消融实验结果:每一个旋钮拧下去,模型都发生了什么
4.1 单变量消融:去重、过滤和配比各自的影响
先看单变量实验,也就是T1到T5和基线的对比。汇总结果如下表(数据已做归一化处理,归一到基线为100):
| 实验组 | MMLU | CMMLU | HumanEval | MBPP | GSM8K | MATH | C4 PPL |
|---|---|---|---|---|---|---|---|
| B0(基线) | 100 | 100 | 100 | 100 | 100 | 100 | 100 |
| T1(宽松去重) | 98.7 | 99.2 | 103.4 | 102.1 | 99.3 | 95.8 | 99.6 |
| T2(激进去重) | 101.8 | 102.5 | 94.2 | 95.6 | 104.7 | 108.2 | 101.9 |
| T3(松过滤) | 99.1 | 98.8 | 99.6 | 98.9 | 98.4 | 96.1 | 99.2 |
| T4(严过滤) | 101.2 | 102.0 | 96.7 | 97.8 | 103.5 | 102.8 | 102.3 |
| T5(强化代码数学) | 101.9 | 101.3 | 108.7 | 109.2 | 106.4 | 109.8 | 98.1 |
这几个数字背后有非常有意思的规律,我一个个拆开说。
去重强度的影响方向是分领域的。T2激进去重让MMLU涨了1.8个点,数学更是猛增8.2个点,但代码能力掉了大约5个点。背后的逻辑很清晰:激进去重把代码领域里大量"同义改写"性质的样本(比如同一道题的不同解法、同一段逻辑的不同实现)全部干掉,这直接打击了代码模型对模式泛化的能力。而数学领域呢?重复样本本来就少,多余的重复更多是"同题不同序"或者"原题加废话",杀掉这些反而让模型更集中地学习数学的本质结构。所以去重强度不是一个"越高越好"或"越低越好"的问题,而是要看目标领域对"重复多样性"的敏感度。
质量过滤的影响让人有点意外——我以为严过滤应该全线提升,但实际上专有领域(代码、数学)反而受损。T4严过滤在MMLU上小涨、在代码和人Eval上掉了3个点以上。原因也不难猜:我的质量评分器天然地偏好"正式、长文、教科书式"的文本,而代码数据中有大量短小精悍的代码片段、注释和issue讨论,这些在语义上跟广告和低质内容接近,被误判掉了。所以严过滤在通用知识上有效,但在专有格式上是个灾难——这提醒我:质量过滤必须分领域设定不同阈值,而不是用一个全局分数一刀切。
领域比例的表现最为直接。T5强化代码数学后,代码和数学全线大涨,代价是C4困惑度略微恶化。这个结果说明:在总数据量锁定的情况下,领域配比是一个"再分配博弈",而代码和数学语料相对于通用语料,在专用能力上的边际收益高得惊人。
4.2 双变量与三变量组合:交互效应中的意外发现
单变量看完了,更关键的在于组合。因为真实落地你不会只拧一个旋钮——生产管线里这些变量是同时生效的。这条信息量很大,我挑几组最值得琢磨的讲。
T6(激进去重+严过滤):这组在MMLU上刷到了102.9,是所有组里通用能力最好的,但HumanEval只有91.8,是所有组里最差的。这很好地验证了前面单变量的结论——两个"提高数据质量"的旋钮叠加,会进一步放大对代码模式的伤害。我当时看到这组数据时心想:怪不得很多只跑通用榜单的团队喜欢堆去重和过滤,因为这组配置确实能刷分,但它牺牲的东西在通用榜单上看不出来。
T7(宽松去重+强化代码数学):这个组合很有意思。比起T5,它把代码HumanEval从108.7拉到了111.2,MBPP到了112.5,但同时C4 PPL掉到了97.2——这是我所有组里面语言建模最好的成绩。为什么?宽松去重保留了代码数据里的改写多样性,让代码模型在生成时有了更多样的模式和词汇选择,这对生成质量是有直接帮助的。相对于T2的激进去重+数学强效果,T7完全是另一条路线:保留多样性 + 偏向代码/数学配比。
T11(激进去重+严过滤+强化代码数学):如果把三个旋钮都拧到"极致"会怎样?答案是通用性能最好的配置之一,MMLU 102.4、GSM8K 107.9,但代码只有96.5,相比T7掉了15个点。这一组的含义很清楚:三个旋钮之间存在强烈的资源挤兑效应,代码领域表现最依赖多样性,任何砍多样性的旋钮都会在代码上留下代价;而数学和通用知识则更依赖精选度和配比偏好,不太需要无限制的重复多样性。
我把所有组的核心结论浓缩成一张决策速查表,方便后面实战参考:
| 目标能力 | 推荐去重 | 推荐过滤 | 推荐配比 | 参考实验组 |
|---|---|---|---|---|
| 通用知识(MMLU类) | 中-激进 | 中-严 | 均衡分布 | T6 |
| 代码生成 | 宽松 | 松-中 | 强化代码 | T7 |
| 数学推理 | 激进 | 严 | 强化数学 | T2或T4 |
| 综合全能 | 中 | 中 | 微强化代码数学 | T5 |
但必须强调的是:这张表只是"我的数据环境+我的评测基准"条件下的结论。换一套数据来源、换一个模型规模,最优配比可能整个漂移。消融实验真正的价值,不是背下这些数字,而是建立对"旋钮如何影响模型"的直觉。
5. 实操复盘与避坑心得:从12组实验里长出来的经验
5.1 实验设计阶段最容易犯的三个错误
在我跑完这一整套实验后复盘,实验设计阶段栽的坑比训练阶段多得多,这里一个一个说。
第一个坑:没有锁死"有效数据量"。其实我第一轮设计时犯了之前提到的基础错误——没有把总训练词元数锁死,导致直接在"数据量不等"的前提上比较。这类对比得出的结论没有意义,因为模型效果差异可能完全是来自于见到的token总数不同,而不是配比差异。修正做法是:各组在训练时用相同的全局步数,但batch size按有效数据规模折减,确保每个模型见到的token总量完全一致。
第二个坑:评测基准太窄。初版我只跑了MMLU和HumanEval,等T1到T5跑完一看,去重强度的变化在MMLU上的区别几乎全在误差范围里。加了CMMLU、MBPP和GSM8K后,差异一下就显现出来了。做消融实验,评测维度一定要覆盖到目标能力的多个切面,尤其是那些你认为"不太可能受影响"的能力——往往差异最大的地方就在那里。
第三个坑:没有做数据留存与审计报告。前面提到了审计,这里展开说一下。如果每组配置跑完,只保留最终训练数据而没有记录各阶段处理的快照,后面做分析时会非常被动。比如我发现T4组严过滤对代码数据打击大,如果当时没有留存过滤前的分布统计,很难精确地判断是"代码低质数据被清掉了"还是"误杀了优质数据"——这两种结论对应的迭代方向完全相反。每一组配置的数据处理流水线日志(各阶段输出大小、领域分布、去重率变化)一定要完整保留,这是你分析结果的唯一线索来源。
5.2 数据管线的隐蔽问题:领域分类器的偏差与去重标定
实际操作中还有两个隐蔽的数据问题,值得单独拿出来讲。
领域分类器有一个很容易被忽略的标签偏斜问题。我的分类器是在人工标注的领域数据集上微调的,训练数据中代码类只占8%左右,这导致分类器在边界情况下的行为非常不稳定。一个包含大量代码块的技术博客文章,经常被分类成"书籍"而不是"代码",导致强化代码配比的实际执行效率大打折扣。T5组预期的代码占比是30%,但事后审计发现实际只有24%左右。修正方法有两步:一是加训练样本,尤其是跨领域样本(技术文档里嵌代码、代码仓库的README、科学论文里的伪代码);二是在配比环节做一个校正乘数,用"该领域的实际占比/分类器预测占比"来修正偏差。
另一个就是去重标定。我前面说的是LSH参数与实际保留率之间的偏移,这里有一个更细的坑——中文和英文的重复特性差异。中英文的N-gram分布差异极大,英文的shingle=5-6比较合理,但中文由于字符密度更高、虚词更密集,shingle长度设到6会把很多完全不相关的句子无意义地Hash成同一类。最终我改成了中英文分别用不同的shingle长度(英文6、中文8),并且在做LSH检索时分开建立索引。这些细节如果不亲自跑一遍数据,光看论文经验很难意识到。
5.3 训练阶段的数据影响:PPL悖论与评测波动
最终训练阶段我也发现了一些值得记录的现象,虽然主线是数据配比实验,但这些观测对理解结果至关重要。
最值得说的是PPL悖论:C4验证集上困惑度最优秀的组(T7、T10),几乎都是"宽松去重+均衡分布"这类保留多样性的配置,而这些组的MMLU往往不是最高的。反过来,那些困惑度变差(数值高)的组(T6、T11),通用能力和数学能力反而突出。这说明PPL更善于捕捉语言的"流畅度"和"分布覆盖度",并不代表能力高低。如果你在监控面板上看到PPL变高就觉得"坏了",很可能错过一组真正提升了推理能力的配置。
另一个是评测波动。7B模型在HumanEval上的通过率,同一组配置连续跑两次评测,绝对差异就能到1.5个百分点。这可比我在T1和T2之间观察到的很多差距都要大。我的处理办法是:每个关键结论至少重复评测3轮取中位数,且用单独的随机种子生成评测顺序。虽然多烧了点评测时间,但换来了结论的可靠性。
5.4 把结论落地到生产环境的四条实操建议
实验做完了,最终要回答的还是"那我们应该怎么配"。根据这一轮实验的收获,我给生产管线定了四条原则,供也在一线调数据管线的朋友参考:
- 去重强度按目标领域分档,而不是全语料一刀切。代码和创意写作数据用宽松去重(保留率不低于70%),数学和百科知识用激进去重(保留率40-50%),效果优于对全量用同一档位。
- 质量过滤必须分领域设定阈值。全局统一的质量分数,在高分端会偏向长文教科文体,而在代码、论坛、对话数据上造成系统性误杀。先按领域群体独立校准再合并打分,是值得投入的方向。
- 领域配比对专用能力的影响,远超通用知识。强化代码数学配比后,代码和数学涨8-10个点,MMLU只涨1个点左右——说明配比是"专注度"的大杀器。如果你的产品是专用模型,不用犹豫,直接大力强化目标领域配比。
- 组合实验优于单变量实验。单变量告诉你每个旋钮各自好用与否,但变量之间的交互非线性的,有时双变量联动(比如T7)的效果远好于两个单变量的简单相加。生产调参时不要只做"一次只动一个变量"的假设。
6. 常见问题速查与后续扩展思路
实验记录整理成FAQ形式,方便有相同目标的人快速找到参考:
Q1:数据总规模不够大,去重到底该松还是该紧?A:规模在50B token以下时,我建议去重偏向宽松(保留率70%以上),因为数据不够多时多样性更稀缺。等总数据超过100B,再去考虑激进去重来提升数据质量。数据量和多样性的权衡比"数字上的干净"更重要。
Q2:质量过滤误杀严重,有什么快速检测方式?A:最有效的方法是在不同过滤档位下分别跑一遍领域主题分布直方图,将过滤前后占比差异超过15%的领域都拉出来人工过目。通常广告识别和代码片段区分是最容易出问题的,可以单独训练一个二分类器处理黑名单,而不是依赖全局打分器。
Q3:强化代码数学配比之后,通用能力掉多少可接受?A:我实测是MMLU掉1个点以内掉得比较正常,如果掉超过2个点,多半不是配比的问题,而是代码和数学数据里混入了低质样本欠了清洗。比例提升前先保证目标领域数据本身过关,否则前置步骤的债会在下游加倍偿还。
Q4:消融实验太贵,能不能用更小规模的代理实验?A:完全可以,但注意代理实验的可靠性。我建议用1B规模的模型做配比筛选,选Top 2后再上7B验证。1B和7B在配比偏好上不完全一致,但方向基本一致。规模扩大到一定程度后,配比影响会进一步放大而不是缩小——用小模型筛选大方向,用大模型做精细校准,比较稳妥。
后续这个系列我会继续做两个方向的扩展:一是把去重算法本身纳入消融(MinHash vs SimHash vs 嵌入向量聚类去重),看不同去重方案对结果的影响是不是比参数差别更大;二是做配比随训练进程动态变化的实验——前20%重通用百科、中间50%铺代码数学、最后30%做指令问答的"课程式配比",看看是否比静态配比更优。从这一轮的静态消融结果来看,动态配比很可能是下一块大肉。
这篇文章写到最后,我想再分享一个我个人的体会:如果你想成为一个真正懂LLM训练的人,数据配比比任何单一SOTA模型结构对你的长期直觉帮助更大。今天很多团队都在刷模型结构、抄最新attention机制,但数据层面几乎没有自己的实验积累。这次消融实验做完,我对"什么数据让模型学到什么能力"有了更踏实的理解——这种感觉不是读几篇论文能替代的。下一次当有人问你"为什么我们模型代码能力不行"时,先别急着改loss和架构,回去翻翻你的数据管线:去重是不是杀掉了代码的多样性,过滤是不是把代码片段当垃圾扔了,配比里代码语料是不是被偷偷稀释了。很多时候,答案就写在这些不起眼的旋钮上。