大模型数据工程实战:清洗去重与配比全解析
1. 数据决定论为什么说训练LLM的本质是在投喂数据做了几期大模型训练连载之后后台问得最多的一个问题是明明按教程走了预训练流程loss也降了为什么生成效果就是不对味这类问题我基本不用看代码就能猜到病根——多半是数据环节出了问题。搞大模型的人常挂在嘴边一句话模型是数据的压缩。这句话的含金量比大多数人想象得高。神经网络的训练过程本质上是在用梯度下降拟合训练集的分布。模型不是“学会”了某种知识而是把训练数据里的统计规律硬生生记在了权重里。你喂给它什么它就长成什么数据里的噪声、偏见、错误格式一个不落全都会在生成结果里复现。这个连载的前两篇讲了架构选型和训练框架搭建那些东西当然重要但到了第三篇我必须把丑话说在前面如果数据没做好后面的一切都是在错误地基上盖楼。llama、bert这些开源模型大家都能下到权重为什么二次训练之后差距越来越大就是因为每个人喂的数据不一样。数据工程在整个LLM训练流程里通常要占掉六成以上的工作量这不是夸张的说法。数据采集、清洗、去重、配比、格式化、token化每一环都有坑而且这些坑不跑到大规模训练阶段根本暴露不出来。很多团队第一版模型效果不好不是模型太小、算力不够而是数据质量没达标。本篇我会把数据处理的完整链路拆开来讲从原始语料的获取到最终喂进训练框架的token序列每一步都说明白为什么要这么做以及做了之后会发生什么。这不是教科书式的流程介绍全是实操中验证过的经验。2. 原始语料获取源头的广度决定模型的上限2.1 数据从哪里来预训练数据的来源相对固定主流的公开语料基本就这几类网页爬取内容、开源书籍、学术论文、代码仓库、百科类结构化文本、社交媒体文本。其中网页爬取内容占比最高像业界常用的几个公开数据集绝大多数token都来自网页。自建语料的话最省事的方案是直接用开源数据集。但这里有个容易被忽视的问题公开数据集的英文占比普遍偏高中文内容质量参差不齐。如果要训练一个中文场景为主的模型纯粹靠公开数据集效果会明显偏科。我见过不少团队的做法是以公开数据集打底自己爬一批垂直领域语料做补充。爬虫方向的选择取决于模型的最终应用场景。做客服机器人就多爬电商评价和售后对话做编程助手就重点抓技术文档和代码仓库做法律咨询就得想办法获取裁判文书和法规条文。数据源规划的核心原则是“先定场景再定语料”。不要为了凑数据量而漫无目的地爬那样只会让模型变成一个什么都懂一点、什么都不精的庸才。目标场景确定之后数据源的选择就清晰了每个来源对应模型要掌握的一种能力。2.2 数据规模怎么定预训练数据的规模跟模型参数量强相关。业界有个大致的经验法则token数量应该是模型参数量的20倍以上。一个7B模型训练数据量最好不低于140B token13B模型对应260B以上70B模型起步就得1.5T往上。这个比例不是拍脑袋定的。模型容量有限每个参数要负责“记住”的统计规律数量是有限的。数据太少模型欠拟合学不到足够的规律数据太多边际收益递减浪费算力。20倍是一个实践中的甜点区间低于这个值模型的困惑度下不来高于这个值提升就很不明显了。这里要特别提醒一点数据量充足的情况下模型的困惑度曲线降不下去十有八九是数据出了问题不是模型架构的问题。很多人一看到loss收敛慢就急着调模型其实先排查数据才是正确的debug顺序。3. 数据清洗垃圾进垃圾出3.1 清洗流程的完整链路原始语料拿到手之后第一件事就是清洗。网页爬取的内容质量参差不齐有大量导航栏、广告、版权声明、乱码文本、敏感词命中内容这些都需要在进入训练流程之前剔除。一套标准的清洗流程包含以下环节编码统一与乱码过滤把所有文本转换成统一编码格式检测并剔除非目标语言的字符序列。中文场景要特别留意繁体简体混用、全角半角混用的情况。内容抽取与模板剥离网页正文抽取去掉HTML标签、导航菜单、页脚版权信息。这一步对爬虫数据的质量影响最大做不好会掺入大量重复模板。规则过滤用正则过滤掉URL链接、邮箱地址、乱码连续串、异常重复字符。连续相同字符出现的比例过高往往是机器生成或复制粘贴的内容。语言识别与质量打分按语言分类筛掉目标语种之外的内容。再用perplexity分数或行长度分布评估文本质量规则上可以直接用语言模型打分低质量文本整体丢弃。清洗的目标不是把所有文本变成统一格式而是降低数据里的噪声比例。噪声比例的容忍度跟数据集规模有关——小数据集必须精洗大数据集可以相对宽松。3.2 敏感内容过滤不可省这一步从合规角度必须做从数据质量角度也必须做。网络语料里含有大量不适合作为模型训练内容的文本直接喂进去模型生成时就会把这些内容以各种形态复现出来。敏感过滤通常分为两层。第一层是关键词加正则的规则过滤命中即弃速度快但覆盖有限。第二层是分类模型过滤训练一个文本分类器对语料做逐条判定准确率更高但需要额外的标注成本和推理资源。实操中我的建议是两层都要有。规则过滤保底分类模型覆盖规则捕捉不到的变体。过滤比例通常控制在总数据量的5%到15%之间如果某个数据源的过滤比例超过20%先怀疑这个源本身选得有问题补数据源比硬洗更划算。4. 去重与去污染数据里隐藏的“作弊器”4.1 为什么必须做去重重复数据对LLM训练的危害比大多数人想象得要严重。最直接的问题就是浪费算力——同样的内容被模型反复学习梯度更新不断朝同一个方向走其他方向的规律被稀释模型泛化能力下降。另一个危害更为隐蔽重复数据会放大某个特定模式在模型权重里的占比。举个例子如果训练数据里大量重复出现某种固定的代码写法模型就会倾向于在生成代码时反复使用这种写法因为它被强化得最多。去重的标准做法是MinHash LSH。先把每条文本转成shingle集合计算MinHash签名再用LSH分桶相似的文本会被分到同一个桶里最后在桶内做精确的相似度比较。相似度阈值一般设在0.8左右也就是说两条文本80%以上相似就算重复。4.2 去污染是评测可信度的前提去污染指的是把评测集数据从训练集里剔除。如果不做这一步模型在评测集上的分数会虚高但这种“高分”毫无实际意义。严格来说这是数据泄漏问题——训练数据里包含了测试样本模型做评测的时候本质上是在做记忆复现而不是泛化推理。去污染的做法是把评测集的问题和参考答案拆成片段构建成去重哈希集合在训练语料切块后同样做哈希匹配上的直接剔除。还有一个容易忽略的细节去污染不只是针对测评集文本本身还要覆盖它们经过改写、翻译之后的内容形态。否则模型依然能通过变体文本学到评测集信息。这是个信息战级别的猫鼠游戏标准做法是使用大规模n-gram重叠检测配合语义近义改写检测。5. 数据配比与混合策略多源数据的“烹饪公式”5.1 配比是模型风格的隐形控制器把清洗去重后的多个数据源混合在一起配比决定权直接决定模型最终表现出的知识结构。这其实是训练LLM时少有的“思想工作”浓度最高的环节它比视觉上更容易被忽视但影响比架构调参大得多。设总数据量为T来源分为代码类占比p_c、网页文本类p_w、书籍类p_b、论文类p_p、对话类p_cv满足p_c p_w p_b p_p p_cv 1。每个来源的数据量通过不同采样倍数放大或缩小最终喂给模型的是一个经过“刻意调节”的分布。常见建议配比区间网页文本50%到70%知识广度主要靠这一块撑起来代码15%到30%推理能力和结构化表达的重要来源书籍论文10%到20%长文本建模能力和深度知识来源对话5%到10%影响模型的交互格式适应性代码数据配比尤其关键。代码本身就是一种高度逻辑化的文本括号匹配、变量追踪、函数调用关系迫使模型学习远距离依赖。业界很多模型在代码配比提高之后通用推理能力也顺带涨了这在多个开源模型的评测里都能观察到。5.2 配比的动态调整配比不是定死就不动的。训练过程中需要每隔一段时间评估一次各数据源的“学习效果”观察对应领域验证集的loss走势。注意不同数据源的loss数值不能直接横向比较——代码的loss天然比自然语言低对话数据也跟普通网页文本不在一个数量级。正确做法是每个数据源单独维护一个验证集各自跟踪自己的loss曲线。某个源loss下降明显变慢甚至停滞就说明这条数据源学得差不多了继续按原比例喂是浪费算力需要降低配比把训练预算让给还没学透的数据源。我自己常用的做法是以5%为步长调整某个数据源的配比观察全局loss是否受益。不要一次性改太多否则无法判断是哪个改动带来的效果。这个调整过程贯穿整个预训练阶段不是一次配置就一劳永逸。5.3 合成数据的用法与风险当某个方向的数据天然稀缺时合成数据是一条绕不开的路。比如高质量的数学推理数据、特定格式的行业问答数据靠爬是爬不到的只能自己构造。合成数据对模型训练是有明确帮助的。数学数据可以显著提升推理能力对话数据能让模型更贴合交互场景。但合成数据的“数字化灰尘”问题不容忽视——生成模型自己产出的文本往往带有某种固定的风格偏见大量喂入会让模型的语言风格变得单一和模板化。我见过一个真实翻车案例某团队用主模型批量生成了一大批对话数据用来训练小模型结果小模型学会了“好的我理解了你的问题”这种模板式开头所有回答都是同一个味道。这说明合成数据质量监控不到位大量低质量模板在训练中被放大了。合成数据的关键在于多样性控制。生成时要引入足够的随机性确保覆盖多种表达方式而不是简单地批量调用模型生成统一模板。更要做好质量门槛低置信度的样本直接丢弃宁可少不可滥。6. Tokenization与打包数据最后一道工序6.1 分词器的选择与训练Tokenizer是整个数据处理链路里最容易被“先跑通再优化”糊弄过去的环节。很多人直接拿现成的大模型tokenizer就用这能省事但代价是分词效率可能损失不少。分词器做得好不好直接影响训练效率和模型效果。分词粒度太粗词汇表过大embedding矩阵占用的参数量飙升分词粒度太细序列变长注意力计算的复杂度跟着上涨。理想的tokenizer应该是在压缩率、词表大小、跨语言能力之间取得平衡。中文场景下有一个特殊问题单字成词的比例高纯BPE分词会把中文切成碎片导致每个汉字的token被反复学习但上下文关联被削弱。实践中比较成熟的做法是在训练语料上训练一个SentencePiece模型设定合适的字符覆盖率和词表大小让中文词语尽量作为一个整体出现在词表里。词表大小一般设置在32K到128K之间。7B以内的小模型建议32K起步更大的模型可以考虑64K到128K。词表太小会显著增加序列长度词表太大则embedding矩阵吃掉大量参数预算。我建议新项目直接训练自己的tokenizer不要省这一步。6.2 packing操作的细节tokenizer输出的一维token数组需要打包成固定长度序列才能喂给模型。业界标准的做法是把多个样本的token首尾拼接一段填满就开下一段这就是packing操作。Packing的核心参数是最大序列长度。这个值跟模型架构的注意力机制强相关常见的选择是2048、4096、8192现在也出现了32K甚至128K的长序列训练。序列长度从2048提升到4096训练成本不只是翻倍——注意力机制的复杂度与序列长度的平方成正比。很多团队一开始就跟风用超长序列实际训起来发现GPU显存根本扛不住只好回退。我的建议是第一版模型先按2048或4096训练跑通全流程之后再考虑长序列扩展。贪多嚼不烂。Packing时还有一个必须处理好的细节拼接边界处理。如果两个不同样本拼在一起模型在这个位置会学到一段“从上下文A突然跳到上下文B”的跨文本依赖对语义理解是有害的。标准做法是引入特殊分隔token或者在处理注意力掩码时把不同样本的关注隔离。用分隔token的方式更简单实践中也更稳定。6.3 训练过程中动态质量控制预处理阶段做完tokenization数据流正式进入训练环节之后质量控制工作并没有结束。大模型训练通常需要数天到数周。跑这么长时间中间一定会出现质量问题比如某个数据分片损坏、某批数据混入异常文本、采样比例跑偏。我的建议是训练脚本里加上实时采样监控——定期从训练流里随机抽取一批样本打印出来人工查看同时记录每个数据源的实际采样占比跟预设的配比对照。有人在样本检查环节发现tokenizer对某些特定符号的处理有bug导致一串字符被切成了几百个token白白占用了序列长度。这种问题不做实时采样监控根本发现不了等发现的时候已经浪费了上千个GPU时。7. 常见问题与排查技巧实录7.1 数据侧问题速查表现象大概率原因排查与修复方式训练loss下降缓慢或停滞数据噪声过高或配比不合理做一次抽样质量审计检查清洗规则是否漏了大量低质文本生成的文本出现大段重复训练数据重复度高模型被反复强化检查去重阈值降低查重相似度阈值重新做去重中文生成质量差中文语料占比不足或tokenizer分词不合理增加中文数据配比重新训练tokenizer并使用中文覆盖率参数评测集分数虚高但实际表现差训练集没做去污染评测数据泄漏建立评测集哈希集合从训练语料中剔除匹配片段某些领域知识完全不会对应领域语料缺失或占比极低补充垂直领域语料提高对应数据源配比对话风格僵硬模板化合成数据占比过高且多样性不足降低合成数据配比增加真实对话数据提高合成数据质量门槛7.2 数据工程师最常踩的三个坑第一个坑是数据源单一化。有些团队为了省事只用了一个公开数据集训练出来的模型知识面明显偏窄。我个人经验是至少要把上网文本、代码库、百科、书籍几个大类都配齐模型才会有那种“见多识广”的表现。第二个坑是清洗规则过度激进。正则表达式写得暴力把包含数字、符号的内容全部过滤掉结果模型对数字的理解能力急剧下降。后来才发现清洗规则把大量包含年份、时间、价格等关键信息的文本误杀了。清洗规则的每次修改都要抽样看效果不要只跑一遍就认定没问题。第三个坑是忽视数据时效性。预训练语料里大比例是历史数据模型对最新事件和概念完全无感。这就要在数据配比里预留一部分“新鲜语料”定期补充让模型能跟上语言变化和知识更新。7.3 一个亲测有效的调试技巧当模型训练效果不理想时不要急着调模型架构或训练超参先做一次“数据切片对照实验”。具体做法是从训练集中按数据源各抽取一小部分组成一个微型训练集在这个小数据集上跑一个极小的模型比如两层transformer看它能不能在对应领域做到低loss。如果小模型在小数据集上都学不好那么问题大概率出在数据质量上——大量噪声会限制模型的学习能力如果小模型能学好但大模型在完整数据集上学不好再考虑调架构或者优化策略。这个方法成本低、定位准我靠它解决过好几次看起来是模型问题、实则是数据问题的疑难杂症。8. 数据配比实验的实操记录纸上谈兵没有说服力分享一个我做过的数据配比实验。某次训练一个中型模型初始数据配比是网页文本70%、代码15%、书籍10%、对话5%。跑了大概40%的训练进度模型在代码验证集上的loss已经趋平但数学推理类评测分数没有明显起色。我把代码配比从15%调整到25%相应砍掉网页文本的比例。又跑了一段之后数学推理评分上升了3个点代码loss在经历一个短暂的抬升之后继续下降。这说明原来代码数据量不足推理能力的提升空间被压住了。后续我又把对话配比从5%提到8%模型生成内容的格式规范性和交互流畅度有了可见的提升。但再往上提到12%之后通用知识的评测分数开始下降说明对话数据挤占了太多通用知识的份额。最后稳定在8%的配比上知识覆盖面和处理质量都处于均衡位置。这个实验让我意识到数据配比没有一个放之四海皆准的值必须针对自己的目标场景反复调优。LLM数据工程不是照着配方做菜更像是在调一杯鸡尾酒糖浆多一泵少一泵口感完全不同。9. 关于数据工程的最后几点感慨连载写到第三篇我越来越觉得大模型训练本质上是一个“数据工程决定天花板、算法工程决定逼近程度”的过程。模型架构再先进训练框架再高效喂进去的数据是脏的、偏的、重复的最终产物一定好不到哪里去。数据工程的工作看起来琐碎且没有太多“技术含量”清洗、去重、配比好像谁都能做。但真正动手之后才会发现每一个环节的决策都会在模型行为上留下深刻的印记。一个数据工程师对数据分布的理解深度很大程度上决定了一个模型最终的质量上限。如果让我给正在准备自己动手训模型的朋友一个最核心的建议那就是在数据准备阶段投入至少六成的精力把每个环节都当成正经技术活来做。少跑一轮实验省下来的时间远不够补数据坑带来的返工成本。下一步该聊训练策略和超参调优了那是另一个同样藏满细节的深水区。等下一篇吧。