说句圈内常说的话:大模型不是设计出来的,是喂出来的。这两年大家聊炼丹,聊得最多的是模型结构、训练框架、并行策略,但真正决定一个模型能走到多远的,往往是那批被反复清洗、筛选、配比过的预训练数据。我参与过几次从零开始整理训练语料的项目,深刻体会到一件事——数据准备就像炼金术,原材料再便宜,火候、配方和提纯手段不对,出来的就不是金子而是炉渣。这篇就把预训练数据准备的全流程掰开揉碎讲一遍,适合刚接触大模型训练、或者已经跑通小规模实验但总被数据质量困扰的开发者参考。
1. 先把账算清楚:数据准备决定模型上限,而不是训练代码 1.1 模型能学的“知识总量”由数据量和数据多样性共同决定 很多第一次做预训练的人容易陷入一个误区:以为模型效果不行就加大参数、调学习率、换并行策略。实际经验告诉我,如果你的数据集只有几个GB,模型参数量再大也只是在背诵那点语料的重复模式,稍微换一个问法就会露馅。预训练的核心目标是让模型从海量文本中学习语言规律、世界知识和推理模式,数据量级直接决定了知识覆盖面的上限。
业内一个比较常见的参考基准是:数十亿参数的模型,通常需要千亿甚至万亿级token的训练数据才比较合理。光有量还不够,多样性同样关键。如果语料全是新闻和百科,模型写代码的能力会很差;如果全是代码或技术博客,模型日常对话的流畅度又会受影响。数据准备的第一步,就是明确你要喂一个什么样的模型,然后倒推需要哪些领域的语料、每个领域大概占多少比重。这个账如果在项目启动时不算清楚,后面所有清洗工作做得再精细也都是白费。
1.2 数据质量差会以三种隐蔽方式暴露 数据质量差并不一定表现为训练Loss不下降,它更多是“悄悄变笨”:
重复数据过多会导致模型严重记忆化,生成时整段背诵训练集中的段落,甚至把抓网页留下的HTML标签当作正常文本输出。 噪声数据(乱码、无意义符号、截断句子)会让模型学到错误的上文下文关联,尤其对中文这种形态变化少的语言,一个错误标点都可能污染整个句子的语义。 毒性或偏见内容无法通过模型结构本身消除,一旦进到训练集,后期对齐阶段要花很大的力气才能压住它的影响,甚至经常压不干净。 这些都是我在实际项目中踩过的坑。某次因为偷懒,在清洗阶段省略了短文本过滤,结果模型生成出来的回答经常带着“请输入验证码”、“404 Not Found”这类网页残留文本,定位问题花了整整一周,最后排查到源头就是数据清洗环节漏了一个规则条件。从那以后我养成一个习惯:每清洗一步,抽一批样人工看看结果,绝不等到训练结束再验证。
1.3 一条完整的数据准备流水线应该长什么样 整个预训练数据准备流程,我习惯把它拆成六个环节:数据采集、解析与清洗、去重、质量过滤、隐私与版权合规处理、配比与采样管理。每一个环节都是一道独立的工序,各自有各自的工具和评估指标,决不能混在一起一把梭。
数据采集定义来源(公开网页、书籍、论文、代码、社区问答等);解析与清洗负责把原始格式转成干净文本;去重负责移除近似和精确重复内容;质量过滤筛掉低价值、有害或偏门的文本;合规处理保护个人隐私与版权底线;配比与采样则决定最终混合训练集的构成和顺序。这篇文章后面每个环节单独展开讲,你可以把这份清单当作一个索引,做一个环节查一个环节。
2. 数据采集与文本解析:从原始HTML里把“正文”抢救出来 2.1 原始语料来源的优缺点盘点 先说数据从哪儿来。最常见的免费高质量来源是公开网页抓取,其次是书籍、学术论文、代码仓库、问答社区、百科等半结构化数据。公开网页抓取语料非常廉价且规模巨大,动辄几十TB,但里面HTML标签、导航栏、广告链接、评论区重复内容极多,噪声大得惊人。书籍和论文质量高、噪声小,但版权风险高、获取成本高。代码数据则必须单独处理,不能和自然语言混用一套清洗规则。
我比较推荐的策略是“金字塔结构”:底层是海量网页抓取数据,用于扩规模和丰富话题;中间层是书籍、论文、百科这类高质量文本,用来提升知识密度和表达规范性;顶层是代码、数学题解、对话片段等任务导向语料,用来增强模型的推理和指令跟随能力。金字塔每一层都需要不同的解析方案,这也是为什么数据准备很难用一个通用工具一杆子捅到底。
2.2 HTML解析与正文提取的最佳实操路径 网页抓下来的数据通常是一个HTML文档,里面有
、<meta>、<script>、<style>、<nav>、<footer>等大量与正文无关的内容。直接拿正则去扣文本是最容易翻车的方法,因为真实网页的嵌套结构和编码问题实在太多。</p> <p>更稳妥的做法是先做标准化解析,再做正文抽取:</p> <ol> <li>用成熟的HTML解析库把文档解析成DOM树,这一步能同时解决标签嵌套和属性提取问题。</li> <li>定义“语义区块”:正文通常位于<p>、<article>、<main>标签内,而<script>、<style>、<nav>、<footer>直接视为无效节点。</li> <li>计算文本密度:遍历DOM树,统计每个节点的文本长度与链接文本比例。正文节点的文本密度高、链接占比低;导航和侧边栏正好相反。</li> <li>按标点符号和段落数量判断文本完整度:一个正经的新闻正文通常包含多个完整句子和句号/问号,广告页则多是碎片化短句。</li> </ol> <p>这套“文本密度+链接占比”策略在实际使用中特别稳,几乎能应付绝大多数传统网页。解析完成后,还需要统一换行符、合并被错误切割的段落、过滤掉控制字符和零宽字符。这一步结束的标志是:随机抽100篇解析结果人工抽查,正文完整率在95%以上才算合格。</p> <h3>2.3 语言识别与语种过滤</h3> <p>采集上来的数据是全球性的,中文模型肯定要把英文、日文等语种的文本剔除,哪怕只留下少量高质量英文,也要明确控制比例。语言识别建议用基于字符特征的语言检测库来做,速度快且准确率高,我也试过用BERT来分类语种,但开销太大了,在大规模流水线上不划算。</p> <p>实际操作中还会遇到中英混杂和方言的情况。比如技术博客里大量夹杂英文术语,直接按语言检测结果把整篇删除会误伤高质量语料。我的处理办法是:按“整篇检测为主,段落检测为辅”的策略走,一篇文档如果80%以上是中文,就保留并标记为中文;如果中文比例低于阈值但英文比例较高,就单独分流到中英混合库,在数据配比环节决定要不要用。</p> <h3>2.4 对有害、垃圾和机器生成内容做第一道拦截</h3> <p>在质量过滤之前,先做一轮粗粒度拦截能节省后续大量算力。规则上优先屏蔽色情赌博类关键词、恶意链接、垃圾广告特征(例如大量“点击领取”“加微信”类短语),同时过滤掉纯乱码字符占比过高的文档。</p> <p>误删问题在这里也值得提一句。有些十几年前的论坛帖子,虽然编排混乱,但回答内容非常有价值;而一些看着清爽的营销软文,反倒没有任何学习价值。所以第一道拦截只做高置信度删除,拿不准的先留下来,交给后面的质量分类器去打分。宁可在这一轮多留一点噪声,也不能把有价值但格式奇特的数据全干掉。</p> <h2>3. 去重是预训练“最不能省”的一环:三层去重怎么做</h2> <h3>3.1 重复数据为什么会“毒害”模型</h3> <p>想象一个人背单词,背了一万遍同一个词,看起来学习量很大,实际上只学会了一个词。重复数据对预训练的影响同样如此:模型容量和训练算力是固定的,重复的token会挤占本该用于学习其他知识的参数空间,还会让模型的输出风格倾向于机械复述。</p> <p>更麻烦的是,网页抓取数据里大量存在“近似重复”。同一篇新闻被多个网站转载后,改个标题、改个首段、加一段免责声明,正文几乎一模一样。这种近似重复没办法通过精确匹配查出来,必须用近似去重算法。</p> <h3>3.2 精确去重、URL去重与MinHash近似去重</h3> <p>在实际工程中,我把去重分成三层,按顺序执行:</p> <ul> <li>第一层:URL去重。网页抓取常常对同一链接抓多次,先把URL标准化(去除统计参数、统一大小写和协议),再直接去重。这层开销最低,能挡掉一成左右的重复数据。</li> <li>第二层:精确去重。对清洗后的文本做标准化(统一大小写、去掉空格与标点),然后计算MD5或SHA1哈希值,用哈希集合判重。这层能去掉完全一样的文本,实施起来非常简单。</li> <li>第三层:MinHash近似去重。把文本切分成n-gram集合,用多个随机哈希函数取最小值,得到文档的MinHash签名,再通过局部敏感哈希把签名相似的文档聚到一起,最后进行相似度比较。相似度超过阈值(比如0.8)的文档只保留一份。</li> </ul> <p>我重点讲讲第三层的参数选择。n-gram的n太大,相似文本无法检出;n太小,容易把正常文本误判为重复。经验值是在中文场景用2到4个字的滑窗,英文场景用5到13个词。MinHash的哈希函数数量直接影响精度,常用的是64到128个哈希函数,配合对应的签名长度,既能控制内存又不会漏掉明显的近似重复。</p> <h3>3.3 近似去重实现中的工程取舍</h3> <p>近似去重是整个数据准备流水线里最费算力和内存的一环,海量文本算MinHash需要大量CPU,存储签名也需要大内存。很多人一上来就上分布式Spark跑,其实数据量在几十GB级别时,单机分块处理加优化后的算法完全能跑完;上到TB级别再考虑分布式也不迟。</p> <p>有个工程细节值得注意:计算MinHash之前,需要先给文本分桶。我通常把文档按照哈希分到100个桶里,每个桶内两两计算Jaccard相似度,桶间不需要比较大量数据。这样能把O(n^2)的比较次数降下来。实测下来,阈值0.8配合单机处理百GB数据,跑一轮大概需要几个小时,属于可接受范围。跑完之后抽样检查召回率,重点看看同一深度报道的不同转载版本有没有都被抓出来。</p> <h3>3.4 一个常见的去重误区:全局去重不等于局部去重</h3> <p>全局去重是整篇文档比哈希,局部去重是检测文档内是否有大量重复的段落。比如同一本书的扫描版在公开网页里出现很多次,全局去重按文档哈希看不出问题,因为页码、页眉页脚都不同,但它本质上仍然是同一本书的内容被重复了几十次。这种情况下需要在文档内部做滑动窗口的重叠检测,把重复片段移除。</p> <p>我的经验是:先做全局去重,再做局部去重。局部去重我用的是“重叠n-gram片段”策略,一句话概括就是:任何一个在语料库里出现超过一定次数的连续片段,都把它单独标记出来并降低采样权重,而不是直接删掉整段。因为有些高频片段是常见的引文或公共表述,比如法律条文、经典诗歌,整段删除反而会丢失合法知识。</p> <h2>4. 质量过滤的“三层筛子”:规则评分、分类器和困惑度</h2> <h3>4.1 基于规则的文本质量信号</h3> <p>去重完成之后,数据里依然有大量“格式正确但内容没营养”的文本。第一层筛子是规则打分,每个评分项都算一个分数,最后汇总成一个规则质量分,低于阈值的直接扔掉。</p> <p>我常用的规则信号有这些:平均句长是否合理(中文句子一般是10到80个字,太长可能是语病或没标点,太短可能是垃圾内容);标点符号密度,正常文本每千字应有20到60个标点,乱码或表格式内容标点密度异常;感叹号比例,营销文常用大量感叹号和夸张词汇,这一特征非常显著;重复性比例,整篇里同一个四字词或短语反复出现,很可能是拼接或填充垃圾。</p> <p>规则筛子最大的问题是太“硬”,容易误杀文风质朴但有内容的技术文档或口语化问答。所以规则打分只做第一道快速淘汰,不追求完美。真正的重头戏在后面。</p> <h3>4.2 训练一个轻量质量分类器并迭代优化</h3> <p>分类器的思路是:把数据分为“高质量”和“低质量”两类,训练一个小规模的文本分类模型,让机器学会判断。轻量级方案可以用FastText或一层Transformer,不需要上亿参数的大模型,关键在于训练数据的标注质量。</p> <p>怎么构造标注数据?我自己的流程是:</p> <ol> <li>从清洗好的语料库中随机抽取样本,覆盖网页文章、论坛问答、论文、代码片段等不同来源。</li> <li>人工标注为“高质量(推荐用于预训练)”与“低质量(不推荐)”,每次标注一万条左右就能启动训练。</li> <li>用分类器对全量数据打分,把得分接近阈值的难例样本拉出来做第二轮人工标注,把错判样本放回训练集重新训练。</li> </ol> <p>这里有个个人体会:与其追求分类器F1分数做到多高,不如认真看看分类器在难例上的表现。难例大多是内容充实但文体特殊的语料,比如个人博客、GitHub README、诗歌散文,分类器很容易把它们误杀。每轮迭代都要专门抽一批难例检查,模型分类的鲁棒性就是这样一点点练出来的。</p> <h3>4.3 用困惑度和现有大模型做第二轮校验</h3> <p>质量分类器偏向“主题和格式判断”,但它捕捉不了语义层的不通顺。这时候可以引入困惑度(perplexity,PPL)来帮忙。PPL的直觉理解就是:用一个语言模型来衡量这段文本有多“出乎意料”。正常文本的PPL很低,乱序、乱码、机器拼凑文本的PPL通常很高。</p> <p>实际操作中,我会用一个小型但训练得足够好的语言模型(几十亿参数量足够)对候选数据做前向计算,统计每个句子的PPL分布。然后按PPL从低到高排序,保留PPL低于P95分位数的数据。这个环节计算量很大,因此只对通过前两层筛选的数据运行,可以省下大量算力。</p> <p>也有团队会用更大的模型做“语义完整性校验”,比如让模型生成下一个句子,看概率高不高。效果确实更好的,但成本也更高。我的建议是:如果你的预算有限,先把规则和分类器这两层做扎实,PPL可以只用来做最后抽检,不需要全量跑。</p> <h3>4.4 三层筛子的执行顺序与耗时分布</h3> <p>三层筛子按顺序可以理解为:规则筛负责“一眼假”,分类器负责“风格和主题不太对”,PPL负责“看起来像人写的但细读不通”。每一层都以上一层的输出为输入,逐级收窄数据规模。</p> <p>从耗时上看,规则筛几乎不占时间,分类器推理是主要开销,PPL是额外开销。我习惯用大数据集在凌晨跑规则筛和分类器,白天调PPL参数,这样能充分利用团队机器的空闲时段。每周跑完一整轮后,抽样人工评估一遍整体质量,形成一个质量报告,内容包括低质量文本的残留比例、高质量文本被误删比例、召回样本示例等。没有这个报告,数据准备永远只能停留在“猜”的状态。</p> <h2>5. 数据配比:最像“手感”又最需要实证的一个环节</h2> <h3>5.1 不同领域数据的目标配比逻辑</h3> <p>清理完单篇质量之后,就要考虑“混合配方”了。配比不只是一个百分比数字,它直接决定了模型最后的擅长方向。</p> <p>举一个中文通用模型的典型配比思路:通用网页文章占40%到50%;书籍和百科类长文本占20%左右;代码和数学类占20%到30%;多轮对话或指令数据占5%到10%。通用文章负责语言基础和知识广度,书籍负责长程依赖和复杂句式,代码数学负责逻辑推理能力,对话负责拟人化和指令理解。如果你做的是代码专用模型,代码和文档的比例可能要提到60%甚至更高,通用文本降到20%以下。</p> <p>配比过程还要考虑数据量本身的有限性。中文高质量书籍文本并不多,想把书籍占比提升到30%都很难凑够量。所以实际项目里经常需要做“降级处理”:书籍不够,就用长篇文章去替代,保持“长文档比例”这个维度不塌掉。</p> <h3>5.2 采样权重、混合路线与epoch的取舍</h3> <p>光有配比还不够,还有一个经常被忽视的变量——不同领域的数据在训练中被repeat(重复训练)多少次。简单把各领域语料拼起来喂给模型,低频领域大概率被高频领域冲掉。标准做法是给不同领域设置采样权重,让低资源领域多被sample几次,找到让每个领域都能学好的权重组合。</p> <p>同时也要控制重复次数。通常建议单条数据重复训练不超过两到三次,让模型见过大部分数据两遍左右即可。经验法则是:把数据按配比混合后做成长序列文件,在训练中用流式读取的方式随机采样,当语料接近耗尽时适当循环,但循环次数过高的领域会挤压其他领域的学习机会。</p> <p>混合路线也一样关键。有人习惯“课程学习”——先喂简单通用数据,再喂代码数学;也有人坚持均匀混合。我认为对当前主流大模型来说,均匀混合配合轻微课程上浮更稳当。一上来就猛灌代码,模型基础语言能力还没建立,代码学得也快不起来。</p> <h3>5.3 别把验证集和测试集污染了</h3> <p>这个问题我放在配比这章讲,是因为它和数据混合方式直接相关。很多公开的开源语料本身带有评测集痕迹,比如各类常见评测问题与正确答案的合集已经被反复收录进抓取库。如果不做清洗直接拿去预训练,模型在评测阶段相当于“看过答案”,指标会虚高得离谱,但真实能力很平庸。</p> <p>实际做法有两层:第一层,建立一个包含常见评测集问题的“敏感样本库”,用MinHash或者Embedding相似度匹配,把语料中包含评测题原题的段落全部踢出去;第二层,预留一部分高质量文本完全不参与训练,作为人员手动评估的私有校准集。私人校准集的好处是不会被任何公开过滤器误伤,能给你一个相对真实的模型能力参照。</p> <h3>5.4 配比调优的实证方法:小规模试配比,大规模定参数</h3> <p>配比不能用一上来就跑几百B token的方式去验证,资源烧不起。更务实的方法是:用一个小规模模型,配上几GB到几十GB的数据,在干净训练环境下跑一个“配比探测实验”。观察不同配比下,模型在代码能力、数学推理、中文理解上的指标变化,然后把最佳配比代入大规模训练。</p> <p>这里注意,小规模实验的结论不一定完全迁移到大模型上,但至少能帮你排除明显错误的配比。我自己遇到过的情况是:某个配比在小模型上看起来不错,放大到几百B token训练后,涌现出极强的重复输出倾向。排查很久后发现是某些领域数据占比太高、epoch数过多导致过度记忆。所以配比参数不是一次性定死的东西,大规模训练初期也要做阶段抽查,随时准备回滚。</p> <h2>6. 隐私、版权与数据版本管理:训练合法且可复现</h2> <h3>6.1 个人隐私识别的实务操作</h3> <p>预训练数据里如果混入了大量真实个人隐私,一旦模型能够背出这些内容,后果非常严重。我处理过的语料里,常见隐私内容包括邮箱、手机号、身份证号、家庭地址、银行账号等。常规对策是先用基于规则的正则表达式批量找出疑似隐私片段,再用一个专门训练的命名实体识别模型补充检测人名、机构名、地址等。</p> <p>识别出来之后不是一概删除。有些文本里邮箱是作者公开发布用来交流的联系方式,删除后不影响内容主体;有些文本整篇主题就是讨论某个具体拆迁地址,删掉核心实体后整段没法读。我通常的做法是:对可以通过替换恢复的实体做脱敏替换,比如把“某市某区某路X号”替换成“[地址]”;对无法替换的整段做删除。脱敏替换会引入一批特殊占位符,这些占位符本身要作为特殊token在词表中预留好,否则分词环节会把它们切得乱七八糟。</p> <h3>6.2 版权与原样数据的博弈</h3> <p>版权风险是预训练数据准备里最难绕开的话题。公开网页抓取容易把受版权保护的内容大规模纳入训练集,一旦原样生成,容易引发纠纷。这个问题没有绝对安全的解法,但有几条缓和策略比较常用:优先使用明确开放许可或者版权过期的资源;对版权高风险来源限制其覆盖比例,而不是整块纳入;在清洗阶段设置版权内容特征词,把部分检测出的整段引用内容过滤掉。</p> <p>作者身份识别也会增加风险,很多抓取语料里包含“作者简介”这类模板内容,它们会加大模型输出与具体人员绑定的概率。我的做法是尽量剥离作者简介、版权声明等页脚信息,这既是为了数据质量,也是为了降低风险。需要声明的是,我这些经验只代表工程实践中的保守做法,具体合规策略务必咨询专业法律意见。</p> <h3>6.3 数据版本管理与溯源</h3> <p>数据准备流程涉及大量变换步骤,如果每一步不做版本标识,最后训练出问题的数据连回溯都没法回溯。我习惯在每个处理环节输出一个带哈希值的清单文件,记录输入路径、处理脚本版本、参数设置、输出文件路径、随机种子等。</p> <p>实际踩坑案例更能说明问题:有一回一个同事修改了清洗脚本中的正则规则,跑完全量清洗后忘了更新清单文件,等到训练到一半需要追溯某个问题文本的来源时,翻了两天才定位到是脚本变更导致的。自那以后,我强制要求所有清洗任务必须自动生成一份数据谱系报告。报告里至少包含来源统计、各步骤丢弃比例、产出版本号、改动记录四项内容。这样一旦模型出现奇怪的生成行为,就能一路追到具体的清洗参数和原始数据样本上。</p> <h2>7. 我在真实项目里沉淀下来的九条经验</h2> <p>到这,预训练数据准备的主要技术流程已经全部覆盖了。干货讲完,最后分享一下我在几个真实项目里沉淀下来的经验,也是我踩坑之后记在备忘录里的重要条目:</p> <p>第一条,永远相信抽样人工审查,不要只看统计指标。指标再漂亮,也不如肉眼看一下30个随机样本感受到的内容真实感来得快。每做完一个清洗环节,都要随机抽查样本。</p> <p>第二条,规则过滤宁松勿紧,分类器判断宁紧勿松。规则写的太死容易整批误杀,分类器可以靠训练样本不断调优,更适合承担比较严格的任务。</p> <p>第三条,去重不是说“数量越少越好”。有些合理的重复是必要的,比如55万条日常对话里必然有大量类似表达,过度去重反而会损失自然语言里本来就有的冗余信息。</p> <p>第四条,隐私过滤优先级高于质量过滤。不要为了追求“语料干净漂亮”,把还带着隐私信息的高质量长文直接放行。</p> <p>第五条,不要追求一次性搞定全部数据。我见过太多团队花三个月磨一个巨型管线的清洗脚本,到头来模型连第一个训练版本都没跑起来。先快速跑出一个只含少量数据的Pipeline,完成一轮小训练,确认全流程通顺后再放量。</p> <p>第六条,配比实验要留足评估时间。配比对了但评估基准选错,也会得出完全相反的结论。通用基测、代码基测、多轮对话基测最好都测一遍。</p> <p>第七条,保存好每一种过滤规则被触发次数的统计。这些统计能告诉你要不要优化规则,也能帮你判断数据源本身的构成变化。</p> <p>第八条,谨慎使用“模型生成数据”扩充语料。先用干净数据训练一个种子模型,再用种子模型生成数据做扩充,这种自举方式容易放大种子模型的错误。要走这条路,必须加非常强的样本筛选和人工抽样把关。</p> <p>第九条,重视语料的“新鲜度”。互联网数据分布变化极快,半年前的语料和现在的语料在热点事件、流行表达上有明显差异。预训练切分时可以考虑给近期数据稍微提高采样权重,让模型对当前世界的了解不过时。</p> <p>数据准备没有一劳永逸的模板,每个项目都要根据模型定位、算力预算、可用语料源去调自己的配方。但这套“采集解析、去重、质量过滤、配比、合规管理、版本追踪”的框架是通用的,照着这个框架一步步搭,至少不会在方向上有大偏差。希望这篇文章能帮你少走一些我走过的弯路。</p>