ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零训练1.3B小语言模型全流程复盘:预训练、微调、蒸馏与DPO

从零训练1.3B小语言模型全流程复盘:预训练、微调、蒸馏与DPO 1. 从哪里开始想为什么一个1.3B的小模型值得从零训练我花了大半年时间把一个代号叫 Xihe 的 1.3B 小语言模型从一片空白的数据开始完整跑完了预训练、继续预训练CPT、监督微调SFT、参数高效微调PEFT、蒸馏和 DPO 的全流程。这篇文章就是这次实战的完整复盘包括每个阶段我踩过的坑和改过的参数。先交代背景。团队当时面临一个很现实的问题业务需要一套私有化部署的文本理解服务要求单机单卡能推理、响应速度快、数据不出内网而且对特定领域术语的准确率要求很高。直接调云端大模型 API 不可行私有化部署一个 70B 模型又太贵——一张 A100 80G 只能勉强塞下 70B 的量化版推理延迟和并发能力完全达不到要求。这时候摆在我面前的选择有三个直接下载开源权重比如 Qwen-1.5B、Llama-3.2-1B然后做领域微调。白嫖别人的 API 做蒸馏用大模型生成数据来训练一个小模型。完全从零预训练一个领域小模型。方案一最省事但问题是开源基座的通用能力和领域术语覆盖不够而且微调空间有限。方案二数据好搞但依赖外部接口和数据不出内网的需求冲突。方案三看着折腾却是唯一能同时满足领域可控、数据私有、推理轻量的路子。所以 Xihe 的定位从一开始就很明确1.3B 参数、中文优先、领域可定制、单机可推理的基座模型。不是要跟大模型比全知全能而是要在垂直场景里做到够用、可控、快。后面所有环节的决策都是围绕这个定位展开的。整条技术链路分成六大块预训练构建通用语言能力底座。CPTContinue Pre-Training用领域语料做定向增强。SFTSupervised Fine-Tuning教会模型按指令回答问题。PEFTParameter-Efficient Fine-Tuning用 LoRA 快速迭代任务适配器。蒸馏向更强模型学习生成风格和逻辑。DPODirect Preference Optimization对齐人类偏好提升回答质量和安全性。每块单独看都不算陌生但串在一起跑完中间有大量网上教程不会告诉你的细节。这篇文章就是把我实际动手的过程、参数、教训全部摊开给想走这条路的人一个完整参考。2. 数据管线预训练语料清洗的逐环节拆解很多人以为预训练嘛拿公开语料直接灌进去就行。我一开始也这么想直到第一次跑出来的模型开口就是网络连接失败和乱码才意识到数据清洗比调参重要得多。2.1 语料来源与配比原则我把语料分成四大类配比为 6:2:1:1类别占比来源通用中文语料60%开源中文维基、社区问答、新闻、百科类文本领域专业语料20%业务方沉淀的技术文档、操作手册、脱敏客服会话代码与结构化文本10%GitHub 许可宽松的代码、JSON、日志模板英文参考语料10%高质量英文科技文章和文档用来保持双语理解力配比不是拍脑袋。通用语料决定模型的语言基础领域语料决定垂直场景的 KPI代码类文本能显著提升逻辑推理能力英文语料则是为了防止模型变成纯中文文盲。我的经验是领域语料比例不建议超过 30%否则模型在通用任务上会迅速退化。2.2 清洗流程五层过滤我搭了一套五层清洗管线按顺序执行暴力去噪去掉 HTML 标签、URL、乱码字符、连续空白。这一步最简单但能干掉 15% 的无效内容。MinHash 去重大语料里重复内容极其严重尤其是新闻稿和百科条目。我用 MinHash LSH 做近似去重阈值设为 0.8去掉重复段落和近乎重复的句子。语言识别过滤纯英文、纯数字、混合垃圾文本全部剔除。用 fastText 的语言识别模型按句子粒度过滤保留中文和合理的中英混合。质量打分过滤搞了一个启发式规则打分器包含句子长度、标点密度、信息熵、是否包含完整句对结构。低于阈值的段落直接丢弃。安全与隐私过滤这是必须有的环节。对文本做敏感词表匹配和 PII个人隐私信息识别身份证号、手机号、银行卡号这些模式全部用正则和 NER 模型筛掉。业务方提供的客服会话数据还会做一次脱敏后才能进语料池。这套管线用 Apache Spark 分布式跑处理 2TB 原始语料大概花了两天。最终清洗完剩下 1.2TB质量明显干净很多。2.3 Tokenizer 训练词表大小和领域词Tokenizer 我踩过一个有趣的坑。用现成的中文 BPE 词表比如 Llama 的词表直接训练领域术语会被拆得七零八落。比如氢燃料电池堆叠工艺参数这种短语标准 BPE 能拆成十几个 token浪费序列长度还学不好术语语义。解决办法是用领域语料单独训练一个新的 BPE tokenizer词表大小设为 64K其中领域词覆盖率提升了约 30%。训练完成后跑了三组测试文本对比通用文本的 token 数基本不变甚至略增领域文本的 token 数下降约 15%-20%氢燃料电池堆叠工艺参数从 14 个 token 降到 6 个 token。别看这个优化小预训练跑几十亿 token 的时候省下的序列长度就是实打实的训练效率。2.4 数据质量验证三板斧清洗完的语料不能直接上还得抽样验证。我自己构建了三个验证维度困惑度抽检用一个小型 GPT-2 模型计算段落的困惑度困惑度异常高超过阈值两个标准差的段落大概率是残次品手动抽查后决定去留。聚类多样性对随机抽取的 10 万条段落做文本聚类看簇的分布是否均匀。如果 80% 的段落集中在同一个主题簇里说明数据源太单一。人工盲看样本每天随机抽 200 条清洗后的段落人工阅读记录发现的问题类型。这个最后一道把关看着笨但实际上最有效。数据管线的总结是预训练效果的上限由数据质量决定而不是模型结构。模型结构抄一个成熟架构就行数据清洗的功夫省不了。3. 预训练阶段从零到 Checkpoint 的执行记录预训练是整个链路里最物理的阶段笨重、费钱、磨人。这套跑下来我对训练稳定的认知完全变了。3.1 软硬件环境与框架选型先说硬件。训练机是 8 卡 A100 80GCPU 内存 1TB处理数据的时候发现 512G 不太够临时扩了一倍GPU 间走 NVLink存储挂的 NVMe SSD 阵列。这套配置大概花了团队一周时间去协调资源。框架选型我在 DeepSpeed ZeRO-3 和 Megatron-LM 之间纠结了很久。Megatron-LM 的张量并行和流水线并行对多机训练效率很高但代码复杂度也高。最后选了 DeepSpeed ZeRO-3理由很现实我们是单机 8 卡ZeRO-3 的纯数据并行模式足够了DeepSpeed 对 HuggingFace Transformers 的兼容性好调试成本低PEFT、蒸馏、DPO 这几个后续环节都深度依赖 HuggingFace 生态。1.3B 模型在 8 卡 A100 上跑预训练显存完全无压力单卡吞吐约 12k tokens/s8 卡合计约 100k tokens/sGPU 利用率稳定在 85% 以上。3.2 架构配置与超参数设定模型结构沿用了一个被验证过的成熟架构标准 decoder-only23 层隐藏维度 204832 个注意力头前馈维度 8192采用 RoPE旋转位置编码、RMSNorm均方根归一化和 GQA分组查询注意力。关键超参数如下优化器AdamW权重衰减 0.1峰值学习率6e-4warmup 2000 步然后余弦衰减到 6e-5Batch size256 个序列每个序列 2048 token即每步 524k token梯度裁剪1.0训练总步数约 4 万步对应约 200 亿 tokenbatch size 和序列长度的选择要解释一下。序列长度决定模型能学到的上下文依赖范围2K 是基线后续 CPT 阶段再拉到 4K。batch size 不能太小否则梯度噪声大、训练不稳定但也不能太大否则每步迭代慢调参反馈延迟高。256 是一个让我睡得着觉的数字。3.3 训练过程中的异常与处理第一个大坑出现在第 3800 步。训练 Loss 原本稳定下降突然从 2.1 跳到 2.4然后各种指标开始乱飙。第一次遇到这种事情我第一反应是学习率太大赶紧停住翻 tensorboard 才发现是数据管线里面有脏数据——几段超长重复日志流进了这条 batch导致梯度爆炸。解决方案是三层防护加载数据时再做一次长度截断和重复模式检测开启梯度裁剪到 1.0已经开了但显然不够改成了 0.5训练脚本增加loss spike 自动暂停逻辑loss 超过移动平均 3 个标准差时自动冻结 checkpoint 并告警。第二个坑是学习率调度。一开始我拍脑袋设了 10% 的 warmup结果前 2000 步模型几乎不收敛后来改成固定 2000 步 warmup 加余弦衰减状态明显好了。经验是不要对超参数自作聪明先抄开源模型成熟的配置再改。3.4 Checkpoint 策略Checkpoint 我是每 1000 步存一次完整权重每 5000 步额外存一次 optimizer state。完整权重用来做下游微调和评测optimizer state 用来回滚恢复。磁盘空间消耗很大每个 checkpoint 约 10GB。跑了半个月之后我开始定期删旧的 optimizer state只保留最近 5 个和关键里程碑。预训练这块的整体体验是它是一个自动化程度很高、但任何一个小细节都可能导致全部返工的阶段。数据没问题、框架稳定、硬件不抖剩下就是等。但等的过程必须时刻盯着 Loss 曲线别指望它自己一帆风顺。4. 继续预训练与 SFT领域适配的关键两步预训练基座跑完后Xihe 已经是一个能续写文本的通用中文模型但离可用还差得远。它不会回答问题更不会按照指令提供信息。接下来就轮到了两件几乎所有小模型项目都绕不过的事CPT 和 SFT。4.1 CPT让模型先认识领域CPT 本质上就是在通用底座上用领域语料做二次预训练。我把它放在 SFT 之前而不是直接拿领域数据做微调。这背后的逻辑是领域知识需要先以语言理解能力沉淀到模型的参数里再通过 SFT 学会如何组织答案。顺序换过来模型很容易只会表面地复制领域话术但遇到训练集外的变体就崩。CPT 的具体操作训练数据20 亿 token 的领域语料全部是清洗后的技术文档、操作手册和脱敏客服会话。学习率降到 5e-5大约是预训练峰值学习率的十分之一。序列长度从 2K 拉长到 4K让模型适应长文档理解。训练步数约 3000 步跑完一遍语料为一个 epoch。CPT 结束后的评测标准很简单领域术语的困惑度明显下降同时通用语料的困惑度不发生大幅回升。如果领域困惑度降了但通用困惑度涨了超过 15%说明模型已经被领域数据带偏出现灾难性遗忘。这种情况下早期可以回滚 checkpoint 降学习率重试但最好还是从根本上控制领域语料比例。4.2 SFT 数据构造质量比数量重要SFT 阶段的目标是把 Xihe 从文本续写器变成能听懂人话的回答器。这一步成败全在训练数据上。我第一版 SFT 数据集是复制网上开源的指令数据集大概 20 万条跑完效果惨不忍睹——模型学会了指令格式但回答内容空洞还经常复读用户问题。后来狠下心砍掉 70% 的低质量数据手工构造了 3 万条高质量指令对效果立刻好了很多。高质量数据的四条标准问题要真实从客服会话和用户反馈提取真实 query不要自己凭空编。答案要权威答案来源是领域专家的审核文档而不是网上随便抓的答案。指令要多样同一个问题至少构造 5 种问法直接问、带上下文问、要求分步骤回答等。拒绝项要有回答不了的问题要明确说不知道不要让模型胡编。例如一条典型的 SFT 数据是这样的{instruction: 电解槽的电压异常升高可能是什么原因请列出排查步骤。, output: 电解槽电压异常升高通常有三个排查方向1. 检查膜电极是否发生降解... 2. 检查催化剂层是否中毒... 3. 检查气体供给压力是否波动...}构造完成后我把数据随机分成 80% 训练、20% 验证并统计了指令长度、答案长度分布确保训练集覆盖多样性。4.3 SFT 训练细节loss mask 是必须的SFT 不是标准语言建模的简单套用关键细节是只计算 response 部分 loss也就是把 prompt 部分的 loss mask 掉。如果不做这一步模型会花大量参数去拟合怎么接用户的话头而不是怎么给出好答案。具体实现用的是 HuggingFace Transformers 的 DataCollatorForLanguageModeling 改造版在 tokenizer 返回的 labels 里把 prompt 部分的 token 设为 -100忽略索引这样模型只对 output 部分回传梯度。其他参数设置优化器AdamWlr2e-5Batch size128梯度累积 8 步实际每步 1024Epochs3并在每个 epoch 结束时跑一次验证集 loss在 epoch 2 之后观察训练集和验证集 loss 差距如果验证集 loss 连续两轮上升就提前停止SFT 阶段跑了大约 6 个小时最终验证 loss 从 1.8 降到 0.9 左右。跑到这一步Xihe 已经能像一个领域实习生那样回答问题了但距离一个可靠的助理还有不少距离主要体现在回答不够结构化、容易啰嗦、偶尔夹带幻觉信息。这些痛点正是后面蒸馏和 DPO 要解决的问题。5. PEFTLoRA 参数该怎么定才不白做理论上 SFT 完可以直接用但到了实际项目里业务方隔三差五提新需求能不能让模型会议纪要整理得更简洁能不能让它把技术文档翻译成小白版本如果每个需求都重新做一遍全参微调时间和算力都受不了。这是 PEFT参数高效微调真正发挥作用的地方。5.1 为什么选 LoRA 而不是全参微调全参微调有三个绕不过去的问题显存和训练时间长全参微调 1.3B 模型需要 8 卡LoRA 只需要一张 48G 的卡就能跑。每训练一个任务都会得出一份完整的微调权重无法模块化管理。与预训练阶段的知识容易互相混淆。全参微调会把模型整体拉向任务分布通用能力下降。LoRA 的思路是用两个低秩矩阵近似权重增量。通俗解释模型的原始权重是一个很大的矩阵 W微调的目标是得到一个新的 W W ΔW。LoRA 把 ΔW 用两个小矩阵 A维度 rank×d和 B维度 d×rank相乘近似只训练这两个小矩阵大幅降低训练参数数量。1.3B 模型全参微调要训练 1.3B 个参数LoRA 可能只需要训几百万个。5.2 LoRA 参数配置实践我试了几组 rank 和 alpha 的组合最终固定了一套稳妥配置参数推荐值说明rank16rank 太小8学不动太大会失去高效的意义alpha32通常为 rank 的 2 倍控制低秩矩阵更新量dropout0.05防止适配器过拟合target_modules[q_proj, k_proj, v_proj, o_proj]注意力层的四个线性投影全接biasnoneLoRA 不训练 bias 部分target_modules 这个参数是最容易忽略但影响最大的地方。一开始我只在 q_proj 和 v_proj 上接 LoRA效果一般后来把 k_proj 和 o_proj 也加上任务指标的提升非常明显。原因是注意力内部的四个投影对信息流动各有贡献如果只改两个模型对上下文交互的拟合能力受限。5.3 LoRA 训练与合并的实操LoRA 训练结束后要把低秩权重合并回原模型。这是通过 peft 库的merge_and_unload()方法完成的。合并后我对比了一下推理速度和内存占用合并前需要同时加载基座权重和 LoRA 适配器推理延迟略高。合并后LoRA 增量与原始权重融合为一个完整权重文件推理速度恢复为基座原速。内存占用几乎没有额外增加。多任务场景下我维护了一套适配器管理目录每个任务一个 LoRAmodels/ xihe-base/ # 原始基座 lora/ meeting-notes/ # 会议纪要整理任务 translate-simple/ # 技术文档小白化任务 qa-internal/ # 内部客服问答任务业务方需要哪个能力就单独加载对应的 LoRA互不干扰。用这种方式我在 PEFT 阶段用 5 天时间上线了 4 个垂直任务适配器而全参微调方案光是每个任务的数据准备和训练周期就要一周。5.4 一个重要的提醒LoRA 不是万能灵药LoRA 在任务适配场景效果很好但我要提醒一句如果任务需要模型掌握全新的知识体系比如一个完全没见过的新领域LoRA 的 rank 有限不一定学得动。这种情况有两种解法先做 CPT把新领域知识灌进基座再用 LoRA 做指令适配。扩大 LoRA 的 rank 到 32 或 64但保留更多的训练数据。我在技术文档小白化这个任务上试过两种方式直接 LoRA 的效果不如先 CPT 再 LoRA。所以现在的经验是知识类需求走 CPT行为类需求走 LoRA。6. 蒸馏把大模型的手感压进小参数里SFT 和 LoRA 解决的是模型能力问题但 Xihe 的回答风格还带着一股机器味——回答短促、缺乏层次、语气生硬。业务方拿它跟市面上主流的大模型 API 对比后反馈大模型的回答更有条理和温度。这个问题的解法是蒸馏。6.1 蒸馏的含义向更好的老师学习蒸馏在机器学习里就是让一个能力强的模型teacher指导一个能力弱的模型student训练相当于老师带学生。教师模型通常是参数量几十倍于学生的大模型我用了 Qwen 系列和业务方私有部署的一个 70B 模型学生就是 Xihe。具体有三种做法软标签蒸馏教师模型对同一问题输出概率分布学生模型在训练时不仅学正确的答案还要学着复现教师输出的概率分布形状。温度参数 T 控制分布平滑程度T 越高分布越均匀、学到的模糊直觉越多。合成数据蒸馏教师模型生成大量问题-答案对学生模型直接在这批数据上做 SFT。这种做法工程上最直接我用的是这个。在线蒸馏教师和学生同步训练学生每步都接收教师的输出信号复杂度太高我没用。6.2 数据构造与质量控制合成数据蒸馏的关键在数据怎么来和数据是否干净。我准备了一个 10 万规模的问题集从真实客服会话和领域文档中提取。然后让两个教师模型分别回答每个问题各生成 3 条候选答案。接着做一个质量筛选用规则检测纯复读、空话和明显截断用语义相似度聚类删除完全重复的候选答案构造一个小型评分器基于 CLIP 文本编码器 简单回归给候选答案打完整性和清晰度分数。最终选出 3.5 万条高分答案作为蒸馏训练集。相对于原始 10 万数据这个筛选砍掉了 65%但训练效果反而更好。训练时loss 由两部分构成标准交叉熵让学生学会正确答案的表述 KL 散度让学生模仿教师的概率分布。总的 loss 是两者加权和我用的是 0.7 的 CE weight、0.3 的 KL weight。温度参数我试了 1.0、2.0、4.0最终在 2.0 上效果最好——既能学到教师的连贯表达又不至于把分布过于平滑影响准确率。6.3 蒸馏后的直观变化蒸馏前后的对比让我印象很深。同样的如何排查电解槽冷却循环故障这个问题蒸馏前模型回答检查冷却循环泵是否正常工作检查冷却液温度检查管路是否堵塞。蒸馏后模型回答电解槽冷却循环故障排查建议按以下步骤进行1. 确认冷却循环泵的运行状态和出口压力是否在正常范围。2. 监测冷却液温度若持续高于设定值需进一步排查换热器结垢情况。3. 检查管路是否存在堵塞迹象可通过压差变化辅助判断。若上述步骤均未解决问题建议联系厂家获取详细的维护手册。明显更有层次、更完整像是站在用户的角度组织信息而不是简单罗列关键词。6.4 蒸馏需要注意的坑蒸馏最大的隐患是教师模型会幻觉。70B 模型也会一本正经地编造领域细节如果直接拿它的生成结果训练学生等于把幻觉刻进学生的参数里。我的对策是对蒸馏数据中事实性强的答案引入人工抽检每批次样本抽 5% 核对领域规范文档同时保留一部分权威语料的 SFT 数据与蒸馏数据混训防止模型完全被教师的生成风格支配。混训比例大概是 3:1蒸馏数据占大头。蒸馏阶段跑完后Xihe 的回答质量有了一次显著跃升。但这也带来了一个新的烦恼模型虽然表达好了但偶尔会给出过度自信但错误的答案。有一次问它一个内部系统配置问题它言辞凿凿地给了一个根本不存在的配置文件路径。这正是下一步 DPO 要解决的让模型学会在不确定的时候正确表达同时更加偏好高质量回答。7. DPO去掉奖励模型的偏好优化实操SFT、蒸馏之后Xihe 已经具备了领域知识、指令遵循能力和较好的表达组织能力。但依然存在 幻觉、过度自信、回答质量不稳定的问题。传统的解法是 RLHF基于人类反馈的强化学习但它需要训练一个奖励模型还要做 PPO工程复杂度很高。DPODirect Preference Optimization给出了一条轻量得多的路径。7.1 理解 DPO为什么可以不用奖励模型RLHF 的思路是先收集人类偏好数据训练一个奖励模型来模拟人类评分然后用 PPO 优化策略模型让回答问题越来越迎合这个奖励模型。DPO 则是一种巧妙的数学变化。它推导出了一个可以直接在偏好数据上做监督学习的损失函数绕开了奖励模型和强化学习采样过程。通俗地说如果一对回答 A 比 B 更好DPO 就直接调大 A 被选中的相对概率同时调小 B 被选中的概率让策略模型学会更偏好偏好数据中的优选回答。它对算力的要求比 PPO 低很多训练稳定也直观。对于 1.3B 级别的小模型来说DPO 是性价比很高的对齐工具。7.2 DPO 数据构造chosen 和 rejected 从哪来DPO 的训练数据格式是三元组(prompt, chosen, rejected)其中 chosen 是更被偏好的回答rejected 是相对较差的回答。构造思路从真实场景收集 2 万条 prompt。用 Xihe 当前版本和教师模型分别生成回答。人工标注偏好对同一 prompt 下的两个回答标出一个更优一个更差。对分歧大的标注做二次审核最终确定训练集。为了让模型见过不同质量的回答我给 rejected 也设计了多样性包括事实错误的回答、逻辑混乱的回答、回答过于啰嗦的回答、语气冷冰冰的回答。这样模型不仅知道什么好还能学会避免哪些坏毛病。一个标注例子{prompt: 电机轴承温度超过 85 度怎么办, chosen: 如果电机轴承温度持续超过 85 度需要立即停机检查。常见原因包括润滑不足、轴承磨损、负载过大或散热不良。建议先停机降温再断电检查轴承润滑状态和负载情况。, rejected: 没事85 度正常继续跑就行。}从例子能看出rejected 不只是字面错误还可能是一种过于随意且不负责的回答态度。DPO 训练会让模型理解给用户建议时要有依据和步骤不能拍脑袋。7.3 DPO 训练实操与参数DPO 训练需要同时加载两个模型一个是冻结参考模型ref model保持为 SFT 阶段的模型权重一个是训练模型policy model初始化同参考模型一样。训练过程中参考模型不更新只用它的输出作为基线政策模型在不要偏离参考模型太远的前提下优化偏好目标。关键参数我经历了好几轮调试参数我的最终值调参心得beta0.3beta 控制 KL 惩罚强度太大模型训不动太小容易偏离参考模型。0.1-0.5 我都试过0.3 最稳学习率5e-6比 SFT 阶段低一个数量级防止一步更新就把 SFT 学到的能力冲掉batch size32DPO 对 batch size 不敏感但每 batch 的 chosen/rejected 必须来自同一 promptepochs1DPO 不建议多轮过犹不及优化器AdamWwarmup 100 步常规配置训练过程观察到 Loss 在前 500 步快速下降然后趋于平稳神奇。大约跑了 4 个小时。训练结束时我在评测集上看到 chosen 方向的相对概率上升rejected 方向下降说明模型确实学会了好坏判断。7.4 评测不能只信自动指标DPO 的效果评测是最容易自欺欺人的环节。我一开始只跑 BLUE/ROUGE 这类自动指标发现分数上涨明显但是人工盲测下来有 20% 的回答仍然带着明显的生硬感。后来我建了一套三层评测体系事实准确率答案中是否出现与领域规范不符的表述由领域专家抽检达到 92%。完整性回答是否覆盖了 prompt 中的所有关键信息点覆盖率从 78% 提升到 96%。偏好分数人工盲测对比 DPO 前后模型的回答偏好率DPO 后的版本在 70% 的样本中胜出。DPO 之后Xihe 的过度自信问题大幅缓解——当问题超出训练数据覆盖范围时模型会给出建议查询内部文档或联系相关工程师确认条件不足时也会主动追问而不是硬编一个答案。这类安全感的提升对要直接面对业务用户的我来说非常重要。8. 那些吞时间的坑中途踩到的异常与最终代价这一节本可以散落在各处我还是单独拿出来总结因为这些坑都直接影响了训练周期和资源消耗也给后来者省点学费。8.1 预训练阶段 Loss Spike 事件前面提过第 3800 步的 Loss Spike但那只是开始。后面整个 200 亿 token 训练周期中一共发生了 4 次异常损失跳升两次源于数据管线混入了低质量日志片段一次源于多卡通信故障导致的梯度不同步一次是热插拔存储设备导致的 checkpoint 加载丢步。前三次都靠回滚 checkpoint 解决第四次直接丢了 2000 步训练成果白白浪费了十几个小时。所以我的经验是稳定职业式训练必须做 checkpoint 全量备份周期并把数据管线和训练解耦——数据管线如果出错不能影响已经稳定运行的训练进程最好把数据解析和模型训练拆成两个进程。8.2 SFT 时的 Quirk模型学会了复读机SFT 阶段第一次跑出来的模型在回答任何问题时都会先复述一遍用户的问题。这个 bug 的根因就是我在 3.3 节提到的——没有做 loss mask让模型把精力花在模仿 prompt上。修复前我慌了很久以为数据有问题重新清洗了数据仍然依旧复读最后才想到是 loss mask 的问题。所以 loss mask 是 SFT 的第一课我把它写在最后是希望大家从第一遍就做对。8.3 DPO 时的 Beta 值陷阱我一开始把 beta 设为 1.0训出来的模型回答变得非常保守所有答案都长得很像而且带有过度的安全修饰语。这是因为 KL 惩罚太大模型为了避免偏离参考模型太远采用了极其平稳的策略。调回 0.3 之后模型既保留了 SFT 阶段的表达多样性又学会了偏好更优回答。这个参数强烈建议做一次坐标网格小实验不要直接盲冲。8.4 算力消耗与时间账单最后报一下成本。整个 Xihe 项目从数据准备到 DPO 完成经历约 4 个月中间有数据等待和业务需求变更的暂停有效训练时间大概 40 天。阶段数据规模训练时长硬件预训练200 亿 token~28 天8×A100 80GCPT20 亿 token~2 天8×A100 80GSFT3 万条指令~6 小时2×A100 80GPEFT/LoRA4 个任务各 5 千条4 小时/任务单张 A100 80G蒸馏3.5 万条合成数据~8 小时2×A100 80GDPO2 万条偏好对~4 小时2×A100 80G累计 A100 卡时约 6,500 小时。如果按云上 A100 每小时几块钱租用费计算训练成本大概在十几万元这个量级。但如果走全参微调的路线每个任务都要 8 卡全参微调累计成本可能翻倍以上。9. 写在最后这条路到底值不值得走从零训练一个 1.3B 小模型这件事如果只看产出可能有些人会说直接微调一个开源模型不香吗。我经历过完整流程后会更坦诚地回答这个问题的答案取决于你的场景。如果你的需求是快速上线一个 demo那开源模型 LoRA 是最优解性价比最高。但如果你和我一样面对的是领域语料私有、推理轻量、持续迭代、答案可解释性要求高的业务那么完整走一遍预训练管线带来的收获远不只是拿到的那个模型权重。最大的增量在于你对数据质量、训练稳定性和对齐链路之间关系的理解是体系级的这种理解会在后续的每次迭代中重复兑现价值。Xihe 项目当前的版本仍然在继续演进。我下一步想做的事包括三件一是把蒸馏数据合成过程做更强的教师模型集成提升数据源头质量二是对 DPO 阶段引入更细粒度的偏好维度比如在事实性、完整性和表达风格分别做优先优化三是继续探索 PEFT 阶段不同任务之间 LoRA 的复合使用策略。最后分享一个小技巧全程保留好每个版本的 Log 文件和 Checkpoint并给每个版本打上 tag注明改动内容。我因为在预训练阶段没有给不同数据清洗版本的模型打 tag后期对比效果时花了整整一天去对照日志和模型版本相当不值。数据、代码、模型、记录四个层面保持一致整个流程的可复现性就成功了一半。
返回列表