拓冰建站拓冰建站
首页 / 资讯中心 / 正文

从零构建大模型全流程:预训练、SFT、DPO与RLHF实战指南

1. 为什么值得从零走一遍大模型全流程很多人做大模型都是从下载一个开源权重、跑个LoRA微调开始的这没什么问题能快速出活。但如果你真想搞清楚大模型到底是怎么“炼”出来的只做微调那一步是远远不够的。你会遇到一堆说不清的现象为什么基座模型有时候答非所问为什么SFT之后模型变“傻”了为什么DPO训练完反而出现重复退化这些问题的根因往往藏在预训练数据配比、SFT样本构造、偏好数据质量这些上游环节里。我这次做的项目就是完整走一遍数据准备→预训练→SFT→DPO/RLHF→评估的全链路。规模上不追求对标千亿参数而是用一个可承受的参数量我选的是0.5B到1.5B这个区间把每个阶段的工程细节和踩坑点都摸清楚。这套流程适合几类人想系统理解大模型训练全貌的算法工程师、需要给团队搭建训练pipeline的技术负责人、以及准备做垂直领域私有模型但不想一上来就烧钱的团队。核心关键词先摆出来大模型、预训练、SFT、DPO、RLHF。这五个词基本就是当前开源大模型训练的标准链路。预训练解决“模型会不会说话”SFT解决“模型听不听话”DPO/RLHF解决“模型说得对不对味”评估解决“你怎么知道它变好了”。下面我按实际执行顺序把每一步的设计思路、参数选择、代码要点和踩过的坑都摊开讲。2. 整体方案设计与关键选型思路2.1 为什么选“小参数全流程”而不是“大参数单阶段”先说清楚一个取舍如果你目标是做一个能打的线上产品直接拿开源基座做SFTDPO是最经济的。但从学习角度跳过预训练你会缺失对tokenizer、数据配比、学习率调度、梯度累积这些底层机制的体感。我选0.5B~1.5B参数是因为单卡A100 80G或者双卡4090 24G就能跑起来预训练一天能跑几十亿tokenSFT和DPO几小时一轮迭代速度快试错成本低。参数量的选择有个经验公式预训练token数约为参数量的20倍Chinchilla scaling law的简化版。也就是说1B参数模型理想预训练数据量在20B token左右。但实际中为了快速验证流程我先用2B~5B token跑通观察loss曲线和生成质量再决定是否扩数据。这个“先小后大”的策略能帮你在早期就发现数据清洗和配比的问题而不是等烧了一周GPU才发现数据有脏。2.2 技术栈选型为什么是这些工具训练框架我用的是PyTorch HuggingFace Transformers Accelerate/DeepSpeed。理由很直接Transformers的模型定义和tokenizer生态最全Accelerate做单机多卡和混合精度最省心DeepSpeed的ZeRO阶段2/3能显著降低显存占用。如果你要上多机再考虑Megatron-LM或FSDP但单机场景下DeepSpeed ZeRO-2足够。数据处理用datasets tokenizers库前者做流式加载和shuffle后者训练自己的BPE tokenizer。评估阶段用lm-evaluation-harness做标准benchmark再自己写一套领域相关的生成质量评估脚本。DPO训练直接用TRL库的DPOTrainerRLHF如果要做PPO用TRL的PPOTrainer配合reward model。提示不要一上来就装一堆框架。先把TransformersAccelerate跑通确认单卡能训练再逐步加DeepSpeed和TRL。环境依赖冲突是新手最大的时间杀手。2.3 全流程阶段划分与数据流整个pipeline我分成五个阶段每个阶段的输入输出必须明确阶段输入输出核心目标数据准备原始文本/对话/偏好数据清洗后的tokenized数据集质量与配比预训练大规模无标注token流基座模型base model语言建模能力SFT指令-回答对指令跟随模型听懂指令DPO/RLHF偏好对/奖励信号对齐模型输出符合偏好评估测试集benchmark指标报告量化效果这个顺序不能乱。我见过有人跳过SFT直接做DPO结果模型连基本指令格式都学不会偏好数据再干净也白搭。预训练是地基SFT是框架DPO是装修评估是验收。3. 数据准备决定模型上限的关键环节3.1 预训练数据的来源与清洗策略预训练数据我主要用三类通用网页文本类似C4、中文维基、领域文档比如技术文档、论文摘要、以及部分开源对话语料。数据量上通用:领域按7:3配比这个比例不是拍脑袋而是因为领域数据太少会导致模型通用能力退化太多则领域适配不明显。清洗步骤我总结成“四去一保留”去重MinHashLSH做近似去重、去噪正则过滤HTML标签、乱码、超短行、去毒关键词黑名单分类器过滤不当内容、去隐私正则匹配手机号、身份证等模式保留高质量长文本。去重特别重要重复数据会让模型死记硬背loss虚低但泛化差。我用MinHash把相似度阈值设在0.8实测能去掉15%左右的冗余。注意清洗规则要可复现。我习惯把每条过滤规则写成独立函数记录每条数据被哪条规则过滤方便回溯。别用一个巨大的正则一把梭出了问题根本查不出来。3.2 Tokenizer训练为什么不用现成的很多人直接拿Llama或GPT的tokenizer用这在微调阶段没问题但预训练从零开始时tokenizer的vocab size直接影响embedding参数量和压缩率。我训练了一个32K词表的BPE tokenizer用SentencePiece实现。训练语料就是清洗后的预训练数据采样100M字符。关键参数vocab_size32000character_coverage0.9995覆盖中文常用字model_typebpe。为什么是32K太小会导致一个中文字被拆成多个token序列变长太大则embedding矩阵膨胀小模型吃不消。32K在中文场景下平均1.5字符/token比较平衡。训练完一定要做压缩率测试拿一段领域文本看tokenize后长度和原始字符数的比值。如果比值低于0.6说明tokenizer对领域词汇覆盖不好需要补充领域语料重新训练。3.3 SFT数据构造质量远比数量重要SFT数据我按“指令多样性回答质量”两个维度筛选。指令类型覆盖问答、摘要、改写、代码、推理五类每类至少500条。回答质量上我坚持三条事实准确、格式规范、长度适中50~500字。太短的回答学不到东西太长的回答容易让模型学会啰嗦。构造方式上我用“人工写种子模型扩充人工校验”的流程。先手写200条高质量种子用强模型生成候选回答再人工逐条改。这里有个坑如果直接用强模型生成的数据训练模型会学到强模型的风格和幻觉所以必须人工介入修正事实错误。实操心得SFT数据里一定要混入5%~10%的“拒答”样本比如“这个问题我无法回答”或“请提供更多信息”。否则模型会对所有问题都强行编答案这在评估时扣分很严重。3.4 偏好数据DPO/RLHF用的采集要点DPO需要的是(prompt, chosen, rejected)三元组。我采集方式有两种一是让模型对同一prompt生成多个回答人工标注哪个更好二是用不同模型生成回答人工对比。每条偏好对都要有明确的偏好理由比如“chosen更准确”“rejected有事实错误”“chosen格式更清晰”。数据量上DPO对数据质量极其敏感1000~5000条高质量偏好对就能看到明显效果但如果有10%的噪声标注效果可能直接归零。我建议至少两人独立标注分歧样本拿出来讨论。偏好数据的分布也要覆盖SFT的指令类型否则会出现“SFT学的技能在DPO阶段被遗忘”的现象。4. 预训练从随机初始化到会说话4.1 模型架构与参数配置我用的架构是标准的Decoder-only Transformer和Llama结构基本一致RMSNorm、SwiGLU激活、RoPE位置编码、GQA分组查询注意力。参数量1.1B左右层数24hidden size 2048注意力头16KV头4。为什么用GQA因为推理时KV cache显存占用能降4倍对后续部署友好。配置上max_seq_len2048vocab_size32000intermediate_size5632约2.75倍hidden sizeSwiGLU的经验值。初始化用normal_(0, 0.02)这是GPT系列的惯例。别小看初始化我试过用默认的Xavier前1000步loss震荡明显。4.2 训练超参与显存优化预训练超参batch_size512通过梯度累积实现单卡micro batch 8累积64步learning_rate3e-4warmup_steps2000weight_decay0.1grad_clip1.0。学习率调度用cosine decay到1e-5。为什么是3e-4小模型可以用大一点的学习率加速收敛1B以下模型3e-4是安全区间再大容易发散。显存优化用DeepSpeed ZeRO-2优化器状态和梯度分片配合bf16混合精度。实测1.1B模型在单卡24G上micro batch 8、seq len 2048能跑起来显存占用约20G。如果OOM优先降micro batch别降seq len因为长上下文能力对后续SFT很重要。# 关键训练循环片段简化 from transformers import AutoModelForCausalLM, TrainingArguments, Trainer import torch model AutoModelForCausalLM.from_config(config) training_args TrainingArguments( per_device_train_batch_size8, gradient_accumulation_steps64, learning_rate3e-4, warmup_steps2000, lr_scheduler_typecosine, bf16True, gradient_checkpointingTrue, logging_steps50, save_steps2000, deepspeedds_config_zero2.json )4.3 Loss曲线解读与训练稳定性预训练loss从初始的10.5左右ln(32000)≈10.4开始下降前2000步下降最快到2B token时loss约2.85B token时约2.4。如果loss在某个值卡住不动通常是学习率太大或数据重复。我遇到过一次loss突然飙升排查发现是某批数据里有大量重复的乱码清洗规则漏了。注意预训练阶段每500步存一次checkpoint别只存最后一个。我吃过亏训练到后期loss震荡想回滚到中间某个点结果只有最终权重只能重跑。4.4 预训练完成后的基座能力验证预训练完先别急着SFT做几个快速验证用固定prompt测生成流畅度比如“今天天气”续写看是否语法通顺测长文本续写看是否重复测领域问题看是否有一些基础认知。这个阶段的模型应该“会说话但不太听话”如果连流畅都做不到说明预训练有问题SFT也救不回来。5. SFT监督微调让模型听懂人话5.1 SFT训练配置与数据格式SFT阶段我用预训练好的基座初始化学习率降到2e-5warmup 100步训练2~3个epoch。数据格式统一成对话模板比如|user|请解释什么是梯度下降|assistant|梯度下降是一种优化算法...loss只计算assistant部分的tokenuser部分mask掉。这个细节很重要如果全序列算loss模型会学会预测用户输入浪费容量。5.2 灾难性遗忘的应对SFT最容易出现的问题是通用能力退化。我的做法是在SFT数据里混入10%的预训练数据纯文本续写让模型在学指令的同时不忘语言建模。另外学习率不能大2e-5是上限再大就会把预训练学到的知识覆盖掉。实测下来混入预训练数据后模型在通用benchmark上的下降从8%缩小到2%以内。这个技巧在垂直领域微调时尤其有用因为领域SFT数据往往很窄。5.3 SFT效果评估与迭代SFT完做人工评估随机抽100条指令看回答是否相关、准确、格式正确。我通常迭代2~3轮每轮根据bad case补充数据。比如发现模型不会做多轮对话就补多轮样本发现模型回答太短就补长回答样本。这个迭代过程比调参重要得多。6. DPO与RLHF对齐人类偏好6.1 DPO原理与实现要点DPO的核心思想是直接用偏好对优化策略模型不需要单独训练reward model。损失函数是L -log(sigmoid(beta * (log pi(y_w|x)/pi_ref(y_w|x) - log pi(y_l|x)/pi_ref(y_l|x))))其中pi_ref是SFT模型冻结beta控制偏离参考模型的程度我设0.1。beta太小对齐效果弱太大容易过拟合偏好数据导致多样性下降。TRL的DPOTrainer用起来很简单但要注意参考模型必须是SFT后的模型不能是预训练基座。另外DPO训练学习率要小5e-7到1e-6训练1~2个epoch就够多了会退化。6.2 RLHFPPO的适用场景RLHF比DPO复杂得多需要训练reward model再用PPO优化。我建议除非你有明确的reward信号比如代码通过率、数学答案正确性否则优先用DPO。PPO训练不稳定超参敏感我调了三天才跑通而DPO半天就出效果。如果要做PPOreward model用SFT模型加一个value head在偏好数据上训练。PPO的KL系数设0.02~0.1clip range 0.2学习率1e-6。关键是reward不能刷太高否则模型会输出reward高但无意义的文本。6.3 DPO/RLHF后的退化排查DPO后常见问题输出重复、长度变短、多样性下降。排查思路先看beta是不是太大再看偏好数据是否有长度偏差chosen普遍比rejected长模型会学会写长。我遇到过一次模型开始重复“好的好的好的”最后发现是偏好数据里有一批chosen是重复文本标注时没注意。实操心得DPO训练时每200步生成一批样本人工看别等训练完再看。退化往往在早期就出现早发现早调。7. 评估怎么知道模型真的变好了7.1 自动评估指标与benchmark自动评估我用三类困惑度PPL看语言建模能力准确率类benchmark如MMLU、C-Eval的子集看知识生成质量用BLEU/ROUGE看相似度。但要注意PPL低不代表生成好benchmark高不代表实际可用。我通常把自动指标当筛子不当最终结论。7.2 人工评估与A/B测试人工评估我设计了一个5分制量表相关性、准确性、流畅度、格式、安全性各1分。每次评估抽200条两人独立打分取平均。A/B测试是拿SFT模型和DPO模型对同一批prompt生成让人盲选哪个好。这个结果比任何自动指标都可信。7.3 领域专项评估设计通用benchmark之外我针对项目领域设计了专项测试集比如技术问答、代码生成、逻辑推理各50条。这些测试集的答案是我自己写的标准答案评估时看模型输出是否覆盖关键点。这个专项评估最能反映模型在目标场景的真实水平。8. 常见问题与排查速查问题可能原因排查方法解决预训练loss不降学习率太小/数据重复看梯度范数、查数据去重调大lr、重新清洗SFT后通用能力崩学习率大/数据太窄跑通用benchmark降lr、混预训练数据DPO后输出重复beta大/偏好数据有偏看beta、查chosen长度分布降beta、重标数据生成乱码tokenizer不匹配检查vocab和特殊token重训tokenizer显存OOMbatch大/seq长看显存峰值降micro batch、开ZeRO评估指标虚高测试集泄漏查数据来源重新划分测试集提示所有排查都要先固定随机种子确保可复现。我习惯在训练脚本里设seed42torch.backends.cudnn.deterministicTrue。9. 一些个人体会和后续扩展方向这套流程跑下来最大的感受是数据质量决定上限训练技巧决定下限。预训练数据清洗多花一天后面SFT和DPO能省三天。另外小模型全流程走一遍比直接微调大模型学到的东西多得多因为每个环节的反馈都很直接。后续可以扩展的方向一是加入多模态数据做图文预训练二是用LoRA/QLoRA做参数高效微调降低显存门槛三是把评估做成自动化pipeline每次训练完自动跑benchmark和人工抽样。如果团队有资源还可以尝试MoE架构在相同参数量下提升容量。最后分享一个小技巧训练日志里除了loss一定要记录学习率、梯度范数、吞吐量tokens/s。这三个指标能帮你快速定位大部分训练异常。梯度范数突然变大通常是数据有问题吞吐量下降可能是显存碎片或数据加载瓶颈。这些细节文档里不会写但实际训练中天天遇到。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门