写到这里,连载的第三篇来了。前两篇我们讲了模型架构的选型和训练框架的搭建,后台收到不少私信,问得最多的一个问题是:“数据集到底该怎么准备?”这恰恰是我写这一篇最想聊透的东西。标题里的“数据怎么喂,模型就怎么长”不是比喻,是事实——在从零训练一个大语言模型的过程中,数据几乎决定了模型的天花板,而架构和算力只是帮你逼近这个天花板的手段。你喂给它什么样的文本,它就会学到什么样的语言模式、知识结构和价值观倾向。用一句大实话概括:数据是模型的“父母”,你得先搞清楚怎么当这个父母。
这一篇我只会讲清楚三件事:训练数据从哪来、怎么处理干净、怎么搭配比例。它适合那些已经跑通了一个小规模语言模型训练流程、下一步想认真把数据管线做扎实的开发者,也适合刚入行、想弄明白“数据工程在大模型里到底占多少分量”的同学。我会结合自己实际跑过的数据管线,把配方和踩过的坑一起交底。
1. 核心思路:先定数据策略,再谈模型训练
1.1 数据质量决定模型上限
我见过太多人把精力全压在GPU上,换更大的显卡、调更长的训练步数,结果模型输出还是惨不忍睹。问题基本不在算力,在数据。模型参数量再大,也只是在拟合你给它看的那些文本。高质量数据能让一个7B模型打出接近13B模型的效果,反过来,低质量数据能把70B模型拖进沟里。这里有个很好记的公式:模型能力 ≈ 数据质量 × 数据规模 × 训练效率。三者是乘法关系,任何一项趋近于零,整体结果就是零。
训练大语言模型不是“喂得越多越好”,而是“喂得越对越好”。所谓“对”,包括几个层面:文本本身没有错误和冗余,内容覆盖了我们希望模型掌握的领域,文字表达符合目标场景的习惯(比如中文模型就要以高质量中文为主),以及数据彼此之间没有大量重复。这四个层面分别对应清洗、配比、语料选择、去重四道工序,后面我会逐一说开。
1.2 通用数据与领域数据的权衡
在确定数据策略时,第一件要拍板的事:你是要一个通用助手,还是一个垂直领域专家?这个决定直接影响数据配比。通用模型需要尽可能广的覆盖面,新闻、书籍、百科、问答、代码、论文全都得有一点;垂直模型则需要把某类数据做深,比如法律条文加裁判文书加律所文书,总量可以小很多,但领域密度的要求极高。
我自己做通用模型时的默认配方是:通用文本占70%(包括网页、书籍、百科)、代码占20%、问答对占10%。如果目标场景是代码助手,代码比例会直接提到40%以上。没有绝对正确的配比,只有适不适合你的目标。训练过程中建议保留一个小规模的验证集,用一系列固定的评测题持续观察模型表现,以此反向调整数据配方,而不是一股脑全丢进去跑完再验货。
提示:数据配比改动一次,相当于给模型的“口味”改一次方向。每改一次,需要至少再跑到让损失收敛才能看出效果,所以尽量用小的实验批次先验证,再全量执行。
2. 数据从哪里来:语料采集与合规边界
2.1 公开数据集与自采数据的组合
数据来源无非两条路:公开数据集和自建爬取。公开数据集的优点是可以快速起步,质量经过社区筛选,缺点是你和大家用的都是同一份料,模型很难做出差异化。常见的公开数据源包括开源社区整理的中英文语料、论文预印本、代码托管平台的数据导出等。自建爬取则可以根据需求定向采集,比如针对某个垂直领域的内容站点,但数据噪声大,清洗成本高。
我的建议是两条腿走路:以公开数据集作为基础底料,用自采数据做差异化调味。底料保证模型能力不掉线,调味料决定模型的实际使用体验。如果你做的是垂直模型,底料比例建议控制在30%-40%,调味料可以占到60%以上。通用模型反过来,底料占大头,调味料控制在10%-15%即可。
2.2 合规红线必须先划清楚
这一条必须放在技术前面讲。训练数据涉及版权、隐私和合规问题,不是技术问题,但技术手段可以辅助规避。实操中我会做四件事:第一,所有数据集都记录来源和授权信息,建立数据溯源清单;第二,对自采数据只保留正文内容,不做用户信息的收集;第三,涉及个人可识别信息(如姓名、身份证号、电话、地址)的内容,统统用规则和模型双重过滤;第四,数据清洗管道里专门加一道数据版权检查,命中已知受保护内容的片段直接剔除。
我踩过一次直接的坑:某个自建爬虫把论坛的签名档和正文混在一起采了,里面全是个人社交账号信息。模型训练完,问它某个领域的知识,它居然能把某位网友的ID和爱好一起吐出来,当场吓出一身冷汗。后来我在管线里加了个人信息识别层,用正则匹配电话、邮箱、身份证号,再用NER模型做实体识别,这才彻底洗干净。合规不是形式,出了问题是真的会出大事。
2.3 数据规模怎么估算
很多人上来就问“我该准备多少G的数据”,其实这个问题应该反过来问:我的模型有多少参数、训练多少步数、采用什么样的学习率调度,然后倒推需要多少有效数据token。一个粗糙的经验公式是:总训练token数 ≈ 模型参数量 × 20~40。也就是说7B模型,大概需要140B到280B token的训练数据。这个数字看起来很吓人,但实际训练时用的多是“多个epoch重复使用”的数据集。
我在做一个小型实验模型时,参数量1.5B,按经验公式需要30B到60B token。真实操作中,我准备的是15B token的原始数据,训练时跑2个epoch,再配合一定的数据增强和重复采样,效果刚好踩线达标。新手容易犯的错误是数据量不够就硬训,结果模型欠拟合,生成出来的句子都顺不下来。宁可数据准备时间多花两周,也别在训练阶段凑合。
3. 数据清洗:把垃圾倒掉,把宝藏留下
3.1 清洗流程的整体设计
从原始文本到可训练语料,我一般会经过这样一条流水线:格式统一 → 噪声过滤 → 语言识别 → 质量过滤 → 去重 → 隐私过滤 → 切分打包。每一步都有对应的工具和策略,下面这张表是我常用的工具组合:
| 处理环节 | 常用方案 | 目的 |
|---|---|---|
| 格式统一 | 自写脚本转换编码、去HTML标签 | 消除格式差异 |
| 噪声过滤 | 规则匹配去除乱码、广告、导航文本 | 降低数据噪声 |
| 语言识别 | 基于字符分布的语言检测模型 | 保留目标语言 |
| 质量过滤 | 困惑度过滤、启发式规则 | 筛掉低质量文本 |
| 去重 | MinHash + LSH | 消除跨样本重复 |
| 隐私过滤 | 正则、NER模型 | 剔除个人敏感信息 |
| 切分打包 | tokenizer切分、序列打包、内存映射 | 高效送入训练框架 |
这一整套流程跑下来,通常原始数据会缩水40%-60%。不用心疼,留下来的才是真正有价值的训练料。
3.2 启发式规则的实用配方
对于技术类文本,我推荐一套非常管用的启发式过滤规则:符号密度、重复度、句子完整度、语言混合度四个维度。符号密度指的是非字母数字字符所占比例,正常情况下中文文本在5%-15%之间,超过25%就可能是乱码或表格碎片;重复度计算文本里连续重复片段的比例,超过20%直接丢弃;句子完整度看是否以句号、问号、感叹号结尾,低于30%说明文本是截断的;语言混合度检测同一段文本里是否混用了多种语言,正常的中文技术文档偶尔夹几个英文术语没问题,但中英混排每句话都交替出现,就得小心是机器翻译的劣质结果。
字段级别的清洗也容易被忽略。比如从网页抓下来的文本,标题里经常带着“_百度百科”“-知乎”这样的站点后缀,正文里夹杂着“点击展开”“阅读全文”这类功能文案。这些噪声模型学起来毫无价值,甚至会让它在输出时带上这些奇怪的口癖。我的解决办法是建一个高频噪声词组表,由规则直接删除,这个表在项目迭代中不断扩充,到后期已经积累了几千条。
3.3 困惑度过滤的操作细节
启发式规则只能筛掉“看起来不对”的文本,对于“看起来很对但内容空洞”的问题,需要用到困惑度过滤。思路是先用一个已经训练好的基础语言模型给每篇文本打分,困惑度越低,说明这段文本越接近模型见过的“正常语言”。低于某个阈值的文本往往很短、很口语化、信息量低,比如“哈哈哈哈”“好的好的”这类;高于另一个阈值的文本则可能是噪音或非目标语言。
实操中我会取所有文本困惑度分数的5%和95%分位数作为上下界,把落在区间外的样本丢弃。有个细节要提醒:基础模型必须和目标语料是同语言的,否则打分没有意义。比如用英文模型给中文文本打分,基本所有中文样本都会落在高困惑度区间,你会把整个数据集误杀。这个坑我见过不止一次。
4. 数据配比:模型的能力版图由比例画出来
4.1 为什么配比这么关键
同样一堆数据,以不同的比例混在一起喂给模型,最后训练出来的模型风格和知识结构完全不同。原因是训练过程中,模型会按照数据分布来拟合条件概率分布。某个类别的数据占比越高,模型在那个类别上的能力就越强,相应的,其他类别的能力就会相对被压缩。
这就好比一个人每天吃的东西决定了他的体格:长期只吃碳水,蛋白质摄入不足,肌肉量一定上不去;数据配比调整也是一样的逻辑,想让模型在代码上表现好,就得把代码数据的“营养比例”拉高。不同来源的数据还有相互促进的作用:代码数据可以帮助模型提升逻辑推理能力,数学数据可以让模型更严谨,问答数据让模型更听话。技能之间存在正向迁移,这是多任务混合训练的理论基础。
4.2 经典配比数据参考
我在多个项目里验证下来,下面这组配比是一个通用模型不错的起点:
- 网页文本(涵盖百科、新闻、社区):40%
- 书籍与长文(涵盖出版物、论文):20%
- 代码数据:20%
- 中英文问答对与指令数据:10%
- 数学与推理数据:5%
- 其他(对话、多语言文本等):5%
这组配比的意义在于:网页文本提供广泛的知识面和语言多样性,长文提供深度的推理链路和完整段落结构,代码数据提升逻辑和工具使用能力,问答数据直接决定模型在交互场景下的表现。指令数据的占比虽然只有10%,但它决定了模型“听不听得懂人话”,所以不能省。
如果是代码模型,可以把代码数据提到40%,网页相应降到25%;如果是数学推理模型,数学数据至少提到15%-20%,同时长文占比要保住,因为推理能力很大程度上依赖长文语料训练出来的上下文建模能力。
4.3 采样策略与超参数调整
数据配比确定之后,具体怎么采样也有讲究。最直接的做法是“按比例拼接”:训练时每个batch严格按照预设比例从各数据源采样。还有一个更细腻的做法叫“动态权重”:训练前期让通用文本占比偏高,让模型先学会流畅的语言表达;训练中后期逐步加大代码、数学和问答的比重,让模型的能力向推理和指令遵循倾斜。
动态权重调整的代码实现不复杂,核心就是为每个数据源定义一个带衰减因子的权重参数。我在自己的训练脚本里加过一个简单实现:
def get_dynamic_weight(base_weight, step, total_steps, target_weight): # 从base_weight线性过渡到target_weight progress = step / total_steps return base_weight + (target_weight - base_weight) * progress然后每个batch采样时,按照各数据源当前的动态权重做加权随机采样。实测下来,这种策略比恒定比例训练出来的模型,在通用对话和专业任务上的平衡性好不少。当然,代价是需要多调两个超参数(起始权重和终止权重),做实验的成本会增加,适合有明确分工的训练团队。
5. 数据去重与增强:看不见的重复是训练的大敌
5.1 为什么必须去重
很多人不理解去重的必要性,觉得重复文本多喂几次不是加深印象吗?大模型训练不是背书,重复数据会造成两个问题:一是过拟合,模型会对高频重复的句子模式产生过度记忆,面对新输入时缺乏泛化能力;二是训练效率下降,重复的token每个epoch都在被重复计算,浪费算力。还有一个更隐蔽的问题:如果数据集中某个来源的文本反复出现,模型会把这个来源的独特风格当成普遍规律,导致输出带有明显的风格偏移。
去重有两个层面:精确去重和模糊去重。精确去重用哈希就行,把整篇文档的hash算出来,重复的直接去掉。模糊去重就复杂多了,要处理部分改写、拼接、转载等情况,工业界最常用的方案是MinHash加上LSH(局部敏感哈希)。MinHash的基本原理是把文本转换成一串固定长度的签名,两个文档的签名相似度越高,说明它们的重复程度越高,然后用LSH把可能重复的文档分到同一个桶里再做精确比较。
5.2 MinHash与LSH的工程实现
MinHash的流程分为四步:分词、计算每个词的hash值、对hash值取最小若干位作为签名、用多个独立的hash函数重复这个过程得到多组签名。LSH的作用是加速检索:把签名分条带(band),每个条带中的子签名完全相同的文档就放进同一个桶,只有至少一个条带命中,才认为两个文档可能重复,需要做进一步验证。
我在实际项目中用过一个开源库实现大规模去重,处理1TB语料大约需要10个小时左右,集群节点多的话还能更快。去重完成后,语料规模通常会再缩水10%-20%,但训练收敛速度和最终效果提升非常明显。这里有个关键经验:去重一定要在质量过滤之后做,否则低质量文本大量重复存在时,MinHash计算量大不说,还会把一些本来有区分度的短文本误判为重复,造成误杀。
5.3 合理的数据增强手段
数据增强不是CV领域的专利,文本数据也有增强空间,但必须克制。大语言模型训练中,过度的数据增强反而会引入人工痕迹,破坏自然语言的分布。我常用的增强手段只有三种:一是回译增强,把中文翻译成英文再翻译回中文,得到表达方式略有不同的同义文本,用在外语数据稀缺的场景;二是掩码增强,随机遮掉部分词语让模型预测,间接扩充训练信号;三是模板改写,把问答对改写成不同句式,提升指令数据的多样性。
我特别想提醒的是别在高规模训练里滥用增强。开源社区里有过一个失败的教训:某团队把增强数据加了40%,结果模型输出开始出现明显的模板化痕迹,说什么都像在念稿子。增强比例我建议控制在总数据量的5%以内,最多不超过10%。
6. 实操过程:从原始语料到可训练样本的完整流程
6.1 管道搭建与中间产物设计
一条成熟的数据管线,中间一定要有清晰的产物接口,方便随时检查和回溯。我的管线每一道工序都会输出一份中间数据文件,文件名带上处理标记,比如raw_20240101.jsonl、filtered.lang.zh.jsonl、deduped.20240110.jsonl。这样任何一个环节出了问题,都能快速定位到是哪一批数据、哪个环节出的错,不用从头跑。
管线的代码建议用Python写,用多进程或者分布式框架(比如Ray、Spark)做并行。单个文件的处理过程尽量无状态,每篇文档的清洗只依赖它自身,不做跨样本判断,这是性能的关键。只有去重和统计阶段需要全局操作,这两个阶段可以单独拆出来做MapReduce式的处理。
6.2 切分与打包的最佳实践
工业界主流的做法是:先用分词器(tokenizer)把文本切成token序列,再把这些token拼接成固定长度的训练样本。这个长度由模型的最大上下文长度决定,我常用的是4096。切分时要注意几点:样本之间需要用分隔符隔开,避免两篇不同文档的token在边界处拼接造成语义污染;长文本超出上限的要截断并加截断标记;为了充分利用样本,相邻样本之间可以设置一个滑窗重叠区,让模型对边界内容也有感知。
打包后的格式我推荐用内存映射格式(如mmap),配合训练框架的数据加载模块,能做到几乎零拷贝地把数据喂给GPU。这一步在千亿token级别的训练中能节省不可忽视的IO时间。新手先用简单的二进制格式+索引文件也能跑,只是读取速度慢一些。
6.3 训练过程实时监控数据分布
当训练开始后,不要只是盯着loss曲线。更重要的监控指标是每类数据的交叉熵损失。如果一个数据源的平均损失明显高于其他数据源,说明模型还没学会这类数据,但权重配比又太高了,导致训练被拖累;如果某个数据源的损失降得非常快而其他数据源还高,说明它对模型梯度的贡献过大,可以考虑降低它的采样权重。
我会写一个简单的监控脚本,每500步输出一次各数据源的损失统计,内容类似这样:
step 5000 | loss overall: 1.982 | web: 2.101 | book: 1.765 | code: 1.903 | qa: 2.150 | math: 2.342 step 5500 | loss overall: 1.974 | web: 2.090 | book: 1.752 | code: 1.905 | qa: 2.140 | math: 2.331看这个输出就能直观地判断当前数据配比是否合理。比如math损失一直居高不下,说明数学语料可能太难或者量太少,模型分给它的训练容量不够;qa损失下降慢,则可能是指令数据的格式太单一,需要增加多样性。原则是:整体损失在降、个别数据源的损失不能和整体脱节太远,否则就得调整配比。
7. 常见问题与排查技巧实录
7.1 训练损失下降缓慢或不下降
这个问题大概率出在两种数据上:一是数据噪声过大导致模型无法收敛,二是文本中混入了大量非目标语言。排查顺序是先看数据质量报告,确认各过滤阶段的数据通过率是否正常;再看tokenizer的词表覆盖情况,如果未登录词比例过高,说明tokenizer训练语料和目标语料差异太大;最后检查是否有短文本过多的情况,大量不足10个token的碎片文本会严重拖慢收敛。
7.2 模型输出重复率高
输出总是重复同一个句子或词组,本质上是训练数据里重复模式太多,或者模型容量相对于数据量过大造成过拟合。解决手段有三个方向:增强去重强度,把重复判定阈值调严格一些;降低某类占比过高数据的权重;或者增加长文和多样性文本的比例,强迫模型学会更丰富的表达。
7.3 模型对某些领域完全无感
比如你明明喂了不少金融语料,模型回答金融问题还是很差。先别急,查一下这些语料在数据管线中的存活率——很多情况下,金融术语里的英文缩写、专业符号会被启发式规则当成噪声误删,等到打包阶段这类数据已经所剩无几。我自己就遇到过病历数据里的诊断编号被正则误判成电话号码而大量误删的情况。解决方案是给领域数据单独配置一套清洗规则,宁可保留一些无关细节,也不能把有效信息杀掉。
7.4 中文数据里混入大量英文怎么办
用语言识别模型逐篇打分,设定保留阈值。中文技术文本里出现少量英文单词是正常的,但如果整篇以英文为主,就需要判断它是否来自中英对照的翻译语料。我的做法是对每篇文本计算中文字符占比,低于50%就直接分流到英文数据集,不参与中文模型训练。另有一种特殊情况:代码文本本身就是中英混杂,这时应以代码类型为准而不是以字符占比为准,所以语言过滤要放在代码数据分离之后。
7.5 数据规模不足时的临时方案
算力有限、数据不足,是很多个人开发者和小团队的实际处境。我的建议是:先砍掉最耗数据的部分——比如书籍类的长文本可以少用,保留网页文本和问答对,因为这两类数据在少样本时对模型能力的提升最明显。把通用模型的参数量从7B降到1B级别,数据需求可以降一个数量级。再用指令数据做高强度的针对训练,让模型在自己擅长的窄领域内做到够用。
8. 我的经验总结与下一步计划
这一篇写下来,基本把我两年多做数据管线的核心经验都交代了。最后再分享几个容易被忽略的细节:第一,原始数据不要直接覆盖,保留一份快照,很多数据问题到最后都需要回溯原始字段才能排查;第二,每个过滤规则都要记录命中数量,数据管线的运行报告是一份极其重要的工程资产,它能帮你判断模型能力问题是数据还是架构引起的;第三,数据清洗规则不要太激进,每条规则的添加都应该有数据支撑,而不是拍脑袋,否则你会发现自己辛辛苦苦把有用的数据全洗没了。
我自己在迭代这批数据管线时,最有价值的体会就是:训练一个大语言模型,真正花时间的地方不是训练本身,而是数据准备。训练跑一周,数据准备可能要花一个月。但恰恰是这一个月的时间投入,决定了训练那一周跑出来的模型是能用,还是只能玩具。
目前我已经把这套数据管线的第一版整理成了可复用的配置模板,下一步打算把文本质量打分模型单独拎出来做一次强化,目标是让“低质量文本”的判断不再依赖固定的困惑度阈值,而是能结合领域知识自适应调整。等到这个模块跑通,我再回来把连载第四篇写出来。