预训练经验

总结一下预训练经验(2025年版)。

(经验思路均有业界文献)。

模型初始化

随机初始化模型参数,进行大规模预训练,收敛到较好效果所需的token数太多了。

早期用Qwen的0.5B/4B之类的小模型结构做实验,从零训了很多T token的通用数据(把网上能找到的数据都下载清洗了),效果也才勉勉强强。不能说差,但是没有什么特别的惊喜,而成本着实是不低的。按阿里云8*H800的机器算,8卡机器一台一个月在10到12万,而10T级别的训练至少也是百卡规模,训练半个月以上的。相比一两T的训练量,成本提到高了十倍,但是效果的提升不是很多,收益比较小。

这时一个自然的想法就是:"有那么多好用的开源模型,能不能用上已有的模型?"。一个方法是直接接着开源模型继续训,但是这样的问题是,没有办法定制我们想要的模型架构和规模。

比如开源模型有7B的,有4B的,有1.5B的,而如果业务上需要一个3B参数量模型,这时就没法直接用开源模型训了。另外即使参数规模对得上,有些也有版权问题,比如Qwen2.5-4B就没有商用许可,所以直接用也有风险。

那么用已有的模型参数进行新模型参数的初始化是一个可行的方法。

1、大模型 → 小模型

比如14B模型可商用,那可以想办法用它来初始化一个初始效果比较好的3B模型。

Sheared LLaMA和Weight Subcloning这两个初始化方法的效果都比较好。这两个方法都是通过参数裁剪,把大的模型裁剪成一个小模型。

Sheared LLaMA要训练一个mask,通过mask给参数的重要性进行打分,然后保留重要性高的。mask所需的训练量并不大,几B到几十B的token就足够了。

一个注意点,mask的训练需要选择质量高的token,比如代码数学知识之类的,不要混太多简单的、质量一般的数据。这个数据的选择和我们训练模型的目的相关,如果你是要做一个代码模型,那么自然在选择的时候就应该使用更多code数据,以保留更多对code数据敏感的参数。

而Weight Subcloning不需要训练,直接用公式计算各个neuron和层的重要度,然后联合相关维度,保留重要度高的就行。计算神经元的重要性的时候,同样需要根据输入的数据来获得激活值。输入数据的选择原则和Sheared LLaMA一样。

Sheared LLaMA由于有训练,裁剪完之后刚开始训练的loss比Weight Subcloning低(Sheared LLaMA跑个几十步就能到2.x的样子),但是跑个一万step左右基本就都收敛到相同水平了,甚至Weight Subcloning在后期的loss还略略低一点(但是在评测任务效果上基本是持平的)。

Sheared LLaMA和Weight Subcloning都有一个限制,就是模型的高矮胖瘦可以改,比如hidden size,head num,layer num,但是模块的类型不能改,比如激活函数或者attention类型,大模型是什么类型,小模型就还得是什么类型。

实践中,把模型参数量裁剪到原模型的1/5甚至再小一点(14B → 7B、4B、3B、2B)都还是work的。

相比随机初始化,Sheared LLaMA和Weight Subcloning达到相同loss和下游任务评测指标所需的token数,要少很多。原本很多T token才能达到的效果(以预训练loss为指标),结合高效初始化和蒸馏,基本百B级别就能达到。

一个经验,在训练过的规模范围里(0.5B-百B)并没有发现从零初始化模型在效果上的优势,所以可以放心使用已有模型的参数进行初始化,而不用担心随机初始化的优化空间更大的情况出现。

2、小模型 → 大模型

上面是针对大规模预训练,从大模型初始化小模型的方法。也有从小模型初始化大模型的方法,比如Bert2BERT和Llama Pro,在一些场景下效果也还可以。

虽然思路比较旧,做法比较简单,但是可迁移性还可以。

个人觉得,这些小模型 → 大模型的方法主要适合小容量、方向明确的训练。通过提升少量参数,获取复杂任务下的一点提升。比如现在要做某个封闭域的对话能力,而且训练数据量比较多可以用来做预训练,那么用这种方法就可以。

但是不要对最终效果抱太高的期望,一般顶多是在一两个点这样的提升水平。

3、dense → sparse

MoE的训练也探索了。MoE模型随机初始化相比Dense更容易遭遇不稳定的loss,经常出现很大的spike,然后需要很长的时间来恢复(不会几百几千步能恢复的,基本上相当于从化神回到筑基水平)。

因为router的存在,MoE模型整体对精度更加敏感。尝试过简单地把混合精度训练改成全单精度训练,整个过程就会稳定很多,但是这样效率也很低,GPU的利用率连50%都不到,成本更高了,不太可scale,做做小模型还可以。

一个经典的初始化方法是Sparse Upcycling。Sparse Upcycling方法很稳,至少是一个效果效率都不错的基线方法。

Sparse Upcycling一般是用同层数、同attention设置的dense模型,通过FFN复制的方式来获得MoE模型。

几个注意点:

  • (1)现在都是使用细粒度专家,一个FFN会被裁剪成多份专家,裁剪之前需要做一些neuron粒度的顺序打乱来帮助打破专家对称性;
  • (2)另外会需要对部分FFN参数进行随机初始化,我们实验了50%99.5%的原参数保留比例,也就是有0.5%到50%的随机参数进行重新随机初始化,结果是50%70%的收敛效果和收敛速度是比较好的。

关于各种初始化的详细内容,可看LLM高效预训练(一)LLM高效预训练(二)

训练数据

包含多个阶段的训练数据。

1、phase1:通用预训练数据

这一阶段数据大部分是真实数据,一些特定领域的比如代码、数学会有合成数据。合成数据的量相对少,而且目的更明确,就是针对下游某些能力的。先看真实数据,合成数据的处理后面讲。

(1)基础清洗

这部分比较老生常谈了。个人经验是,现在能够收集到的数据量已经非常足够,所以基础清洗可以狠一点,不怕错杀:

  • ppl:太高和太低的都不要
  • 格式:太多分行的,太多短词的(比如疑似网页导航栏),通通不要
  • 长度:太短的不要
  • 其他规则:url/数据类型/字符比例/安全相关字词/日志识别/带太多重复内容的(引起LLM复读机)
  • ...等等等等

再加上人工打标数据训练出来的二分类模型(轻量级的比如fasttext或者小Bert/GPT),把低质量的筛掉。

更多细节可参考Llama3.1--预训练要点一览Qwen2技术报告细节。

(2)去重

去重可以说是提升通用数据质量最为重要的一步,用minhash做文章/段落粒度的去重。minhash的效率还是比较可以的,如果有集群可用。可以先把minhash都算出来,再进行去重处理。

去重的原则是宁杀错不放过,因为重复数据对模型的能力影响很大。

(3)分类

代码数据、数学数据、高教育性数据(比如chinese-fineweb-edu这种)的挖掘,还有通用数据的标签打标,比如体育、音乐、时政等等。好消息是这些基本有可用的体系和模型,可以在已有资源的基础上稍作修改就行。

经验上是提高education score,代码、数学、知识类数据的比例对整体效果有一些帮助,用更少的训练量就可以达到更低的loss。

个人经验,配比可以不用做得那么细,比如在第一阶段中代码数学数据到底占30%好还是40%好,不是最重要的,反正比自然比例高就可以了。在预训练的早期,还是需要通用数据来提升模型基础语言能力的,没有这个为基础,直接学难度大的效果并不好。

2、长文本预训练数据

长上下文的训练所需的数据比较少,业界经验是几B到几十B就完全足够了。

把多个不怎么相关的文档拼接在一起,可以用,但是效果不好。因为这样相当于只是训练了位置编码,和Positional Skip-wise的效果差不多。

略好一点的方法是拼接相关文档,比如论文,把有reference关系的文章拼接在一起。

更好的长文本数据是天然的长文本、有长上下文依赖的文本,比如书籍,特别是大学课本这种,逻辑清晰的。另外,github的项目也是长文本。

长数据在领域分布上有bias,因此筛选的时候记得统计一些这些数据的领域分布情况,需要的时候调整一下,避免分布过于集中。

有一些文章提出构造阅读理解之类的长文本,比如拼接10篇文章,然后再最后提几道题,每道题需要阅读不同的文章来回答。实践上,预训练加这种数据没什么太大的提升。

长文本的相关内容可看Qwen2.5-1M技术解析LLM长上下文的问题解锁大模型长上下文能力大模型推理窗口-从有限到无限大

3、退火阶段数据

很多模型都证明了,LR退火阶段对提升模型最终效果很重要。而这个阶段提升数据质量的收益很大。模型在使用时所需的能力主要是语言能力、知识储备和推理能力。

推理能力主要来自数学和代码数据,知识储备主要来自educational data(比如学科试题、教科书),语言能力则是高质量网页数据。

高质量网页数据主要是从真实数据里用比较严格的阈值筛选的,教科书也都是真实数据,除此之外,学科试题、数学、代码都混了大量的合成数据。

总结下学科试题、数学和代码数据的合成,合成数据都是使用LLM生成的。

(1)多样性

合成数据最重要的就是多样性。没错,先不谈格式、类型、质量,最重要的就是多样性。因为用LLM合成数据,结果都和模型预训练学到分布很相关。

一个提升多样性的方法是利用解码的随机性,提高温度,提高top k/top p等。这是一个方法,但是为了保持合成数据质量,随机性也不能提得太高,特别是针对数学和代码这种准确性要求比较高的场景。基本上通过解码生成多条之后再进行质量筛选,也就能留下几条,而且这几条相似度还是高的。

另一个方法就是通过prompt来提升多样性。同样的prompt输出的结果相似,那就用很多种prompt。腾讯的Persona Hub就很好用。Persona Hub给了10亿个不同的人物描述,我们可以把这些不同的描述加到prompt里,比如生成数学题:


prompt = """

根据以下任务的描述,想象一个其日常生活中的场景,出一道和这个场景相关的数学应用题。

人物描述:{persona}
"""

person = [
  "一个23岁的卡车司机,身高178cm,短头发,单身,爱吃海鲜...",
  "小A,一个化学家,北京人,本科就读于...",
  ...
]

由于人物的描述各不相同,最终输出的结果多样性就比较高。

在这个基础上,还可以加入其他维度的参数,提升多样性。比如:

  • 难度等级:题目的难度,低、中、高,或者小学,初中,高中,大学,考研等,再细一点也可以
  • 话题:可以从persona提取top k个人物关键词,比如"职业"、"学习"、"日常"、"水果"等,然后随机选择一个,要求模型出题必须和这个或者几个关键词相关
  • few-shot example:我们已经有一些高质量题目数据集了,可以从里面随机挑几条,排列组合,和persona一起,一方面提升多样性,一方面也能提升合成数据的质量
  • etc.

总结来说,就是生成的prompt里需要有一个随机数,这个随机数是以自然语言的形式存在的,这个随机数约多样,生成多样性越好。

(2)质量

对于数学、代码和知识考题类的数据:

  • 模型越大,效果越好
  • 专门模型比通用模型效果好

质量评判的时候可以直接LLM-as-judge来给数据质量打分。也可以用已有的开源模型打分,比如huggingface上就有给代码/数学质量打分的模型。

代码还可以通过执行反馈来确定代码是否正确,OpenAI有提供工具。

在这个基础上,一些数据进化的方法也可以用来提升数据的质量和难度,不过这个最好根据数据类型来定制进化的流程。

更详细内容看训练数据合成(一)训练数据合成(二)训练数据合成(三)

训练

1、蒸馏

就是student模型学习teacher模型的logits。

随机初始化的模型所需的token数多,蒸馏起来成本高。但是用大模型初始化的模型,所需的训练token小很多(<=10%),因此蒸馏是个好选择。

一个好的选择是蒸馏的teacher模型和用于初始化小模型的大模型是同一个,或者用同系列的更大模型,这样出来的效果相比直接训练有提升。

蒸馏温度有个先高后低的设置,这样训练的前期学习的范围更广,而后期专注收敛到更好的水平。

2、Maximal Update Parameterization (µP)

MuP是个模型参数化的方法,通俗地说就是设计模型的超参。用这个方法初始化的模型可以保证在不同规模下,训练的LR和BS可以通用。

这个方法的本意是利用小模型调参,然后直接迁移到巨大的模型,从而减少调参成本。不过MuP的参数化方法和通常的模型有些不同,这就可能导致模型最终收敛的效果不一定和通常的模型一致。

不过实验下来确实MuP的训练超参迁移能力不错,大小模型之间的一致性比较强。

而如果要训练的模型比较小,直接网格搜就行了(比如用10B数据),然后看哪个组合loss下降地快,简单粗暴有效。

3、LR:WSD和Cosine

一般训练的LR是warmup + cosine。

WSD的好处是方便做实验。因为cosine要预先设置训练步数,而WSD可以在中间任何时候进入下一个阶段。

效果上,同样的训练token数下,WSD是不如cosine的,至少在S阶段时这样。要把WSD的效果提上来,D的阶段要足够长,最终的LR要足够低,期间的数据质量要提高。

4、多阶段退火

这个是比较重要的。

LR退火阶段是提升模型效果指标的关键。这个阶段要提升数学、代码、学科、和高质量通用数据的比例。

但是实践中,发现退火阶段直接把多种高质量数据混在一起,无论怎么调比例,都会出现跷跷板效应:代码数学加多了,可能通用能力就变差了,或者学科数据加多了,数学就受影响了。

因此退火阶段不直接混在一起训,而是分成多个小阶段,每个小阶段主要训一种数据,这样还可以调LR和BS。

训练单一一种数据的时候,还需要调配内部的数据比例。比如代码数据,合成的要多少,python要多少,其他语言要多少,题目要多少,github项目要多少,这些都需要搜索配比。

确定了配比之后,先分别用单一一种数据,测出每种数据的最佳LR。业界现在的经验是:

学科 > 数学 > code > 通用 (> Tool Use)

因此小阶段的训练也按这个顺序来排,最先训学科,最后训通用。

(1)step 1:学科

这一阶段主要提升学科能力,对标的评测数据主要是MMLU、Ceval和CMMLU这种。

这一阶段使用较大的LR(3e-4),数据主要包含教材(30%),合成的学科选择题(50%),小部分的通用选择题(10%),还有小部分的通用数据(10%),总共xxxB token的数据。(虽然总的数据有这么多,但是最佳checkpoint往往在训练完一遍数据前就达到了。)

通用数据主要是维持一下模型的语言能力,不要因为学习学科知识和做选择题给搞得不会说话了。

以Qwen2.5为基座,训完这一阶段之后,MMLU、Ceval的效果其实就已经明显超过Qwen官方模型了。

(2)step 2:加上数学

在第一阶段的基础上,加入60%的数学数据。这里做过实验,发现再进一步提升数学数据的比例,效果也不会有进一步提高了,甚至有点下降,并且由于学科数据更少,导致学科能力也下降更多。因此从全局分数的出发点考虑,只加入了60%的数学数据。整体的数据比例是 学科:数学 = 40%:60%。

这一阶段训练中,学科能力得分会比第一阶段低,但是会比传统那种一开始就直接混合多种数据的做法要高。这一阶段训练完之后Ceval还能比Qwen2.5基线高6分左右。

这一阶段训个xxB token,数学能力也达到最佳,而学科能力略下降之后也稳定了。

加入的数学数据里依然有大量的合成数学题,主要覆盖中学和大学的各种数学考题。学习率上,发现小一点更好,比如业界训通用数据基本上用1e-4比较多,那对于数学LR=8e-5就比1e-4好。

(3)step 3:加上代码

一个在业界已经验证了的规律:数学和代码能力有一定的相关性,也就是数学能力的提升有助于提升代码能力,反过来也一样。因此这一阶段使用的代码数据比例没有特别高,差不多40%就可以了。整体的数据比例是 学科:数学:代码 = 20%:40%:40%。

学科减少的比例更大一些,因为学科数据在退火阶段训练的时间最长(各个step都有),而且早期的LR更大,所以整体来看,即使在后面的阶段减少比例,学科能力也不会下降太多。

这一阶段LR = 5e-5,训练量也是几十B token。

(4)step 4:综合提升

这是退火的最后阶段,也是预训练的最后阶段,这一阶段会加上一些通用的数据,用来保持语言能力,也会加上一些SFT阶段的数据,让模型的评测效果进一步提升。比如我们想要增强模型的Tool Use能力,所以加入的SFT数据就有不少function call的数据。

大致的数据比例是 学科:数学:代码:通用:SFT = 15%:25%:25%:10%:30%。

LR = 3e-5,一直decay到0了,总共也是训练了几十B数据。

注意这么多阶段中,没有一条数据是重复使用的,所以准备退火数据的时候要预留多一点。

5、batch内数据分配

训练中,每个batch都是按我们想要的数据比例混合。

在构造batch的时候,会一直跟踪各类数据的token数据,保证比例是按预定比例来的。

评测

评测的数据主要是两类。一类是opencompass的数据集,主要测试模型的代码、数学、语言、知识能力。还有一类是更具体的下游任务数据,比如Tool Use任务的评测集,或者业务相关的数据集。

评测的时候,既要看opencompass的通用能力指标,也要SFT之后看下游任务的指标。要注意的是,这二者的关系并不总是正相关的。

另外预训练loss和任务的评测指标也不总是正相关,大致上来说是“loss低不一定效果好,但是loss高效果一定不好”。


【推荐文章】
- Agent:
Agent完全手册(零):三大模块,三个理念
DeepResearch的报告生成方法
从RAG到DeepSearch
agent调研(1)--MetaGPT,OpenManus和OWL
- MoE:
DeepSeek-V3细节探索
MoE模型的前世今生
DeepSeek-V2和MLA
昆仑万维-SkyworkMoE
成本10w刀的JetMoE
MoE的top-p routing
对MoE模型的一些观察
从dense到MoE -- sparse upcycling
MoE路由--expert choice routing
- 端侧模型:
苹果智能系统模型--AFM
MiniCPM
适合移动设备的语言模型--MobileLLM
phi系列模型
Gemma2
苹果的OpenELM
bilibili的index-1.9B
- 预训练:
Qwen3实测&技术报告
代码大模型(一)--业界现状
代码大模型(二)--OpenCoder
LLM高效预训练(一)
LLM高效预训练(二)
Llama3.1--预训练要点一览
Qwen2技术报告
Yi技术报告-划重点看细节
InternLM系列模型
GLM4报告的一些技术点
从Yuan2.0到Yuan2.0-M32
从loss视角理解大模型涌现能力
- 数据:
训练数据合成(一)
训练数据合成(二)
训练数据合成(三)
LLM预训练数据策略(一)
预训练数据处理--长度分解
- 长上下文:
Qwen2.5-1M技术解析
LLM长上下文的问题
解锁大模型长上下文能力
大模型推理窗口-从有限到无限大
prompt压缩(一)
prompt压缩(二)
reasoning压缩(一)
- 推理加速:
大模型推理加速-投机解码
大模型推理加速-MEDUSA
- 对齐:
深度求索DeepSeek-R1详解
基模型Cognitive Behaviors对RL的影响
Llama3.1--post-training要点一览
模型平均 -- model soup
大模型偏好对齐-DPO
大模型偏好对齐-ODPO
大模型偏好对齐-simPO
大模型偏好对齐-IPO
- Transformer:
理解Attention:从起源到MHA,MQA和GQA
LLM的重复生成和ICL
transformer中normalization的二三事
从代码实现看normalization-到底做了什么
稀疏注意力计算:sliding window attention
理解LLM位置编码:RoPE
RoPE的远距离衰减
LLM水印
- 训练框架
LLM训练框架:从优化器和精度讲到ZeRO
LLM训练各种并行策略
- 项目应用:
一个模型支持智能助手系统
关于The Bitter Lesson
- CV:
CV入门--关于Vision Transformer
CV入门--无监督学习
- 多模态:
多模态入门(一)--CLIP
多模态入门(二)--Flamingo,LLaVA系列和BLIP系列
多模态入门(三)--MiniGPT4,DeepSeekVL,InternVL系列和QwenVL系列
多模态入门(四)--CogVLM,VILA,MM1,MM1.5和Pixtral-12B
多模态入门(五)--InternVL系列
小米的移动UI多模态模型--MobileVLM
DeepSeek-VL2的细节
- 大模型算法题:
(1)(2)(3)(4)(5)(6)(7)(8)(9)

Reference

【1】长文详解--LLM高效预训练(一),https://www.linsight.cn/dcb57672.html#sheared-llama
【2】LLM高效预训练(二),https://mp.weixin.qq.com/s/S_Nx5I4C2gxwumG4GMxkDg?token=1318369845&lang=zh_CN
【3】LLM高效预训练(一)https://mp.weixin.qq.com/s/_3-hX3e1TqGEOo6O41JJ_A?token=1318369845&lang=zh_CN
【4】LLM高效预训练(二)https://mp.weixin.qq.com/s/S_Nx5I4C2gxwumG4GMxkDg?token=1318369845&lang=zh_CN
【5】训练数据合成(一),https://mp.weixin.qq.com/s/R1DbxO9lF3xSp2j-Q5-IKQ?token=1318369845&lang=zh_CN
【6】训练数据合成(二),https://mp.weixin.qq.com/s/B6CclTLHvjI03itaSySj9Q?token=1318369845&lang=zh_CN
【7】训练数据合成(三),https://mp.weixin.qq.com/s/LRy0zC9fen8m7XpK1TsB7A?token=1318369845&lang=zh_CN
【8】MiniCPM,https://mp.weixin.qq.com/s/qxr62jbqjf4wr1YJ-P6haQ?token=1318369845&lang=zh_CN
【9】Qwen2.5-1M技术解析,https://mp.weixin.qq.com/s/VpX8ODoSTzw4FJmzB9kTug
【10】LLM长上下文的问题,https://mp.weixin.qq.com/s/Ci9tAMIER0Aj96sK81HNcw?token=1318369845&lang=zh_CN
【11】解锁大模型长上下文能力,https://mp.weixin.qq.com/s/FTewPxSr5fcwkxAgRZm7Wg?token=1318369845&lang=zh_CN
【12】大模型推理窗口-从有限到无限大,https://mp.weixin.qq.com/s/NaTtwURRw7lsG55QTIaVsA?token=1318369845&lang=zh_CN