这两年大家都在聊大模型但真正动手从零训练一个小语言模型的人还是少数。我自己花了将近一个月用开源工具把一个纯实验性质的小模型 Xihe 完整跑了一遍预训练、CPT、SFT、PEFT、蒸馏、DPO每一环都没有跳过。今天这篇文章就把整套决策思路、具体参数和踩过的坑写出来适合那些不想只调包、想搞清楚一个 LLM 从无到有全生命周期的工程师和学生。我会尽量说人话也尽量把“为什么这么做”讲透而不是甩一堆可以照抄但不一定理解的操作命令。先说结论如果你只是想做一个通用聊天助手直接下载现成的开源权重最省事。但如果你需要完全掌握数据配比、词表、训练细节或者想在小团队、小预算条件下把整条管线跑通那从零训练一个小模型是性价比极高的选择。Xihe 这个名字没什么特殊含义就是我自己给实验模型起的代号。下面按完整流水线顺序展开。1. 先想清楚为什么从零训练Xihe 的定位与预算1.1 从零训练和下载现成模型的本质区别很多人看到“从零训练”第一反应是不理解开源社区已经有一堆预训练语言模型随便下一个不就行了吗这句话对通用场景确实成立但“从零训练”和“下载现成权重再微调”解决的问题本质上不一样。下载现成模型相当于精装修二手房到手后改软装效率确实高但你没法换户型。体现在技术上就是词表不是你自己定的里面中文字符切得碎不碎你说了不算预训练数据配比不是你决定的模型当前积累的知识边界也不是你设计的更关键的是如果你想针对某个垂直领域比如法律条文、内部文档、古籍、特定产品话术做深度优化现成权重的数据分布和你真正需要的数据分布之间有一道很难跨过去的坎。从零训练则相当于自己买地盖楼。地基用什么材料、每层楼多高、窗户开多大全都可以按需求来。代价是成本高、周期长、工程细节多。Xihe 这个项目之所以选择从零做是因为我想跑通一条完全可控的玩具级生产线从清洗语料开始体验一个 Base 模型怎么从随机权重变成能对话、能守规矩、能对齐偏好的完整过程。这个经历对理解微调、RLHF 替代方案、模型收敛问题都特别有帮助。1.2 目标模型规格与实际预算Xihe 的规格我最终定成了两档一档是 0.5B 参数用于快速验证流程另一档是 1.3B 参数作为最终实验基线。结构上采用目前主流的 decoder-only Transformer具体配置类似 LLaMARMSNorm、SwiGLU 激活、RoPE 位置编码词表是单独训练的 32K 中文 BPE。为什么选 1.3B 而不是直接上 7B原因很现实1.3B 在消费级多卡上训练可控单卡推理也毫无压力而且很多实验现象比如学习率敏感度、灾难性遗忘、偏好对齐漂移在 1.3B 已经体现得很明显。你用 1.3B 踩过的坑放到 7B 以上一样会遇到只不过换了个更大的台阶。预算方面只按预训练阶段算一笔账。假设用 1.3B 参数、5B token 数据量训练总计算量大约是 FLOPs 6ND也就是 6 × 1.3e9 × 5e9 ≈ 3.9e19 FLOPs。用 8 张 H100单卡稠密算力约 989 TFLOPS按 30%-45% 的实际利用率估算纯计算时间大概在 4-6 小时。如果换成 8 张 4090利用率低一些大概要 2-3 天。这只是预训练后面还有 CPT、SFT、蒸馏、DPO所以完整流程建议按一周左右的机器时间来规划。如果预算紧张把模型降到 0.5B数据量也降到 2B token预训练时间可以直接缩短一个数量级整条流程仍然能跑完。1.3 小语言模型的独特价值和适用边界小模型经常被拿来和大模型对比效果但这其实混淆了目标。小语言模型的价值从来不是超越大模型而是在特定约束下做到“够用且可控”。比如单位内部的知识助手、教学用的示例模型、需要低延迟离线部署的边缘场景1B 级别比 7B/13B 有优势得多。另外小模型的失败模式也是学习大模型技术最好的教材。参数少意味着容量有限它会把训练数据里的问题赤裸裸地暴露出来数据里有重复它就学会复读数据里废话多它就口若悬河但空洞偏好数据质量差它立刻变成“谄媚怪”。这些现象在 7B 上也会出现但小模型出现得更快、更明显定位起来更容易。所以 Xihe 这个项目的真正定位不是一个“能打的模型”而是一条“能跑通、能调参、能理解问题”的完整流水线。2. 预训练与 CPT先把 Base 模型造出来2.1 数据准备小模型比大模型更依赖高质量语料预训练的第一步不是写代码而是洗数据。一个大模型可能靠着超大数据量硬扛数据噪声小模型没有这个余量脏数据会直接体现在困惑度和生成质量上。我 v1 版本直接用了一个开源中文语料包大概 200GB 原始文本。清洗流程我分成了四步第一步去 HTML 标签、控制字符、零宽字符把所有不可见字符清掉第二步做精确去重和近似去重近似去重用 MinHash 加 SimHash阈值设在 0.85 左右把重复段落占比压到 1% 以下第三步做语言过滤和质量过滤保留中文、英文和代码用困惑度过滤掉乱码和拼凑文本第四步是检查标点符号和段落结构不能为了一味“干净”把所有标点都删掉标点是模型学语法的重要线索。数据配比我最终选了中文 70%、英文 20%、代码 10%。这个比例没有绝对最优可以根据后续应用场景调整。但有一点一定要记住小模型学不完海量语料所以数据质量远比数量重要。宁可只留 5B token 的干净语料也不要硬上 50B token 的低质量文本。2.2 Tokenizer 训练词表是模型理解中文的底层视角很多教程会直接跳过 tokenizer 训练直接拿现成词表用。但既然是从零训练Tokenizer 这一关绕不过去。我用 SentencePiece 或 Hugging Face Tokenizers 库训练了一个 BPE 词表语料只用了清洗后数据的抽样部分约 1 亿 token。词表大小定为 32K不要盲目追求大词表因为 embedding 参数会跟着膨胀1.3B 模型在 32K 词表下的 embedding 矩阵只占很小一部分但如果你把词表提到 100K存储和显存开销都会明显上涨。最关键的一步是在训完词表之后做“中文可读性检查”。我拿“人工智能”“自然语言处理”“甲骨文”这类词去分词观察它们被切成了几个 token。如果常见的领域专有名词被切得过碎说明 BPE 训练语料的覆盖不够或者参数不合适。Tokenizer 的好坏直接影响后续所有阶段的性能这个环节值得多花几小时反复验证。2.3 预训练超参与训练细节预训练阶段我用的是 1.3B 配置序列长度设为 1024全局 batch size 控制在 0.5M token 左右。8 张卡的情况下单卡 batch 是 32 条序列全局就是 256 条序列但 1.3B 模型在 4090 上放不下这个 batch所以实际用了梯度累积把物理 batch 拆小累积步数按显存调整。学习率我优先尝试峰值 1e-3warmup 500 步采用 cosine schedule 衰减到 1e-4。如果你发现训练不稳定先降到 5e-4不要纠结。小模型把学习率调大一点通常能加速收敛但梯度 norm 一旦超过 10就要警惕发散。混合精度我用的是 BF16它比 FP16 稳很多基本不用处理溢出问题。梯度裁剪开在 1.0。预训练跑完后的 base 模型不需要能“对话”它的任务是续写文本。判断预训练质量的指标是困惑度和 loss而不是生成效果。我跑 5B token 后 loss 降到 2.2 附近说实话这个量级下 base 不算训透但作为后续阶段的基础已经够用了。如果你想更接近理论最优按 Chinchilla 的估计1.3B 模型可能需要 20B 以上的训练数据但这个成本在小项目里不太现实。2.4 CPT让通用基座变得更懂目标领域如果你的语料已经以中文为主其实可以不做 CPT。但如果后续要接入法律、医疗或者某个垂直领域CPT 就非常关键。CPT 全称是 Continual Pre-Training在已有模型基础上用领域语料继续做自回归训练。做 CPT 最大的坑是灾难性遗忘。本来 base 已经学会的通用知识你用领域语料一冲击可能迅速退化。我的处理方法是领域数据和通用数据按 1:2 的比例混合训练学习率从预训练的 1e-3 级别大幅降到 5e-5 级别训练步数控制在预训练总步数的 10%-20% 以内。观察指标不能只看领域困惑度还得同时盯通用困惑度如果通用 PPL 突然暴涨就说明回放比例不够。这里顺带提一句很多人搜“RoBERTa 中文预训练模型”以为那可以作为生成模型的基座。其实 RoBERTa 这类模型是针对分类、NER 等判别任务的网络结构是 encoder-only不是生成式 LLM 的架构。视觉那边常有人搜 YOLOv8 预训练权重下载那本质上是迁移学习里的“复用预训练权重再微调”思路和 NLP 里的 checkpoint 复用一个道理但和语言模型的从零预训练是两码事。如果要做生成老老实实把 decoder-only 基座训练好不要指望拿判别模型的权重来续写。3. SFT 与 PEFT让模型学会指令跟随3.1 指令数据怎么构建和筛选有了 base 模型之后模型还是一个“续写机器”你问它问题它不会按对话格式回答只会按概率续写。SFT 阶段就是教会它“用户说什么、助手答什么”的交互模式。数据格式我用的很朴素的 JSONL 结构包含 instruction、input、output然后按自定义的对话模板拼成一条完整文本。模板长这样用户消息用特殊 token 包裹助手回复用另一个特殊 token 包裹训练时只对助手部分算 loss用户部分在 label 里全部置为 -100否则模型会学着把用户问题也复述一遍损失函数的方向就错了。数据量方面我实测对 1.3B 模型来说 1 万到 3 万条高质量指令是甜点区间。少于 5 千条模型学不到模式多于 5 万条非常容易出现重复输出和过度背诵。SFT 数据的质量筛选比数量更重要。我做了三件事第一按输出长度过滤少于 20 个字的删掉第二做全局重复筛选确保没有大量雷同话术第三随机抽 100 条人工看重点检查格式是否统一、答案是否明显错误。如果你接到的数据来源是大模型生成的抽检更要严格因为大模型也会一本正经地胡说八道。3.2 SFT 训练细节与收敛判断SFT 阶段的超参和预训练完全不同。预训练学习率可以用 1e-3SFT 全参微调我建议从 2e-5 到 5e-5 之间试起。epoch 不要贪多1 到 2 轮就够了。loss 降低速度和预训练相比会快得多因为模型只需要调整到适合当前任务分布的参数状态而不是从零学语法。一个经常被忽略的问题是“不要只看 token 平均 loss”。SFT 阶段经常出现训练 loss 已经非常低但实际生成质量很差的怪现象。原因是模型可能把助手模板背下来了回复却空洞套路化。我习惯在训练过程中每几百步保存一次 checkpoint然后用固定测试集做生成测试肉眼判断输出是否自然。自动化指标只能辅助SFT 阶段的最终标准必须是“抽看生成的文本”。如果你发现模型训练完之后只会回“好的请问还有什么可以帮您”这类话大概率是数据里这类套话太多。不要试图靠调高采样温度来掩盖必须回到数据层面删掉同质化输出。3.3 PEFTLoRA 和 QLoRA 到底怎么选PEFT 的全称是参数高效微调核心思想是冻结大部分模型权重只训练少量新增参数。现在最常用的就是 LoRA写成矩阵形式就是 W′ W BAB 和 A 是两个低秩小矩阵通过低秩分解把更新量约束在一个很小的子空间里。我用的 LoRA 典型配置是 r16、lora_alpha32、lora_dropout0.05target_modules 覆盖注意力层和 FFN 层也就是 q_proj、k_proj、v_proj、o_proj、gate_proj、up_proj、down_proj。embedding 和 lm_head 一般不做 LoRA因为这两个地方对生成的影响很敏感训练不稳定。用 PEFT 库的写法非常直接from peft import LoraConfig, get_peft_model lora_config LoraConfig( r16, lora_alpha32, target_modules[q_proj, k_proj, v_proj, o_proj], lora_dropout0.05, task_typeCAUSAL_LM, ) model get_peft_model(base_model, lora_config) model.print_trainable_parameters()那到底什么时候用全参 SFT什么时候用 PEFT我的经验是如果模型只有 1.3B而且你已经决定只做一个最终模型那全参 SFT 并不会贵到哪里去效果通常是最稳的。LoRA 的真正价值在于三件事显存不足时救命、需要同时保留多套风格时做到可插拔、以及快速做 A/B 实验时不用反复复制完整权重。QLoRA 更加激进把基座模型量化到 4bit 再加 LoRA适合在单卡上微调 7B、13B 甚至更大模型。但 Xihe 本身只有 1.3BQLoRA 就不太必要了。LoRA 的实战经验还谈不上完美它往往能达到全参微调八成到九成的效果但在知识密度高、推理链路长的任务上差距会更明显。rank 不是越大越好我试过 r64在小数据量上反而更容易过拟合。如果数据量不大r16 是一个稳重的起点。4. 蒸馏让小模型借大模型的判断力涨知识4.1 蒸馏的核心逻辑不是复制权重而是学习判断模型已经能对话了但效果离大模型还有明显差距。蒸馏阶段要做的事情是让大模型当“老师”把它的知识和判断方式迁移到小模型上。蒸馏不是直接复制大模型的权重而是让小模型学会“在哪些答案之间做选择”。老师傅带学徒有两种带法一种是把每个动作的发力方式拆解出来一点点讲——这对应 logits 蒸馏另一种是直接让学徒做大量练习老师在旁边批改——这对应行为蒸馏。对语言模型来说前者需要师生模型共享完全相同的词表因为 logits 是按词表维度对齐的后者则没有这个限制更通用。对 Xihe 来说我训练的小模型词表和绝大多数开源大模型都不一样所以 logits 蒸馏做不了。但这不代表蒸馏无法进行把大模型生成的答案当作新的 SFT 数据本质上就是一种蒸馏。这条路线网上一般叫“指令蒸馏”它实现简单、效果显著是小模型获取高质量行为模式的主流方式。4.2 logits 蒸馏的参数设计和实现要点如果以后你的学生模型和老师模型词表一致可以尝试离线 logits 蒸馏。做法是先把大模型在大量固定 prompt 上的输出 logits 提前算好并缓存然后让学生模型在这些 logits 上学习。温度是 logits 蒸馏最核心的超参。常规做法是将 logits 除以一个温度 T 再做 softmax让概率分布变得更平滑这样“次优答案”之间的差异也能被小模型学到。T 一般取 2 到 5。损失函数是学生分布的 KL 散度加上硬标签的交叉熵两者按权重混合。因为 KL 散度对温度缩放后的 logits 梯度会有 T² 量级的变化所以训练时要乘回 T²否则实际学习率会被带偏。伪代码大致长这样teacher_logits teacher(input_ids) # 提前缓存 student_logits student(input_ids) T 3.0 loss_kl kl_div( log_softmax(student_logits / T), softmax(teacher_logits / T), ) * T * T loss_ce cross_entropy(student_logits, hard_labels) loss loss_kl alpha * loss_ce这个方案的坑在于对齐细节prompt 的 padding 方式、序列长度截断策略、位置编码偏移都会影响 logits 分布。如果 logits 对不齐蒸馏效果会非常差而且不好排查。我个人的建议是只有在你确实需要极限压缩模型且词表一致的前提下才选择 logits 蒸馏否则无脑用行为蒸馏更省心。4.3 行为蒸馏实操用大模型生成 SFT 数据我把大模型当成“数据生产机器”先收集了一批 seed 问题然后用大模型批量生成答案。seed 问题主要来自开源指令集、网页问答和我自己手写的覆盖性题目最终筛出 2 万条左右作为蒸馏数据。大模型生成答案时我调的温度在 0.7 到 0.9 之间太低容易模板化太高会胡编。生成完以后清洗流程和 SFT 数据一样去重、过滤空回复、过滤明显格式错误然后人工抽检 200 条。这里要特别强调行为蒸馏最大的坑是大模型自己也会“翻车”如果种子问题带有诱导性或者生成内容包含错误知识小模型会原封不动学会。我最后会在数据里混入 20% 到 30% 的人工高质量答案用来对冲大模型的固定语气和潜在错误。行为蒸馏的训练目标就是普通 SFT区别只在于数据来源。跑完之后用同样的测试集对比上一步 SFT 全参模型我发现 Xihe 在开放域问答上的通顺程度明显提升幻觉比例也有所下降因为“老师”提供的答案通常更有逻辑层次小模型模仿这种结构后输出不再碎片化。4.4 蒸馏后的评估方式蒸馏后不能只看 loss因为小模型可能只是“学会了老师的口吻”并没有真正记住更多知识。我的评估分两层一层是固定指令集上的自动指标包括关键词命中率、答案长度、重复率另一层是人工打分把 SFT 版和蒸馏版的输出并排放一起盲评。盲评结果比任何指标都直观小模型有没有把大模型的“骨架”学到一眼就能看出来。这里提醒一句蒸馏之后模型的参数量和推理速度完全不变提升的是数据效率和监督信号强度。所以不要期待蒸馏能让模型“变聪明”到超越理论容量上限它只是让模型在同样规模下发挥得更充分。5. DPO轻量级对齐不碰 RLHF 也能有偏好5.1 DPO 和 RLHF 的本质区别对齐阶段传统方案是 RLHF先训练奖励模型再用 PPO 去优化策略中间涉及大量工程细节包括奖励模型的校准、PPO 的 KL 惩罚、各项超参的平衡对 1.3B 这种规模的实验来说性价比很低。DPO 出现后这条路径被大幅简化了。DPO 的核心思路是直接通过偏好数据构造优化目标不再单独训练奖励模型也不再需要强化学习。它假设存在一个隐含的奖励函数通过“chosen 回答优于 rejected 回答”的约束去调整策略分布。训练目标是让模型提高 chosen 答案的概率、降低 rejected 答案的概率同时用参考模型ref model当作锚点防止模型偏离 SFT 后的分布太远。DPO 的 loss 可以简写成这样L -log σ(β * (log πθ(y_w) - log πref(y_w) - log πθ(y_l) log πref(y_l)))其中 y_w 是更优回答y_l 是更差回答β 控制偏离参考模型的强度。这个式子看起来很抽象但直觉很好理解如果模型对 chosen 和 rejected 的得分差距越大loss 越小β 越小模型越被允许在偏好数据上大步修改。对 Xihe 这种小项目来说DPO 的优势非常明显训练稳定不需要维护多个模型和采样环节数据只需要 prompt、chosen、rejected 三要素几千到一万条偏好对就能看到效果。这比 RLHF 动辄要搭一堆组件友好太多了。5.2 偏好数据从哪来偏好数据的构建是最容易偷懒、也是最影响 DPO 效果的地方。理想情况下你需要对同一个 prompt 有两段答案一段明显更好、一段明显更差。数据来源有三类第一类是人工标注质量最高但成本也最高第二类是模型对比用多个大模型生成多个回答再人工或规则评选优劣第三类是让一个大模型同时扮演生成者和打分者先产出多个答案再用评委指令打分排序。我实验时用的是混合方案找了一批种子 prompt让两个不同参数规模的开源模型分别生成回答再用一个更强的模型当裁判投票选优劣。裁判也会误判所以 final 前抽了 500 条人工复核把明显不合理的样本剔掉。最终留下约 8000 条有效偏好对。数量不需要多但 chosen 和 rejected 之间的差异必须要明显。如果两者只是措辞小差别DPO 基本学不到东西。数据格式长这样{ prompt: 给我解释一下什么是梯度消失。, chosen: 梯度消失是指反向传播时梯度逐层变小导致前面的层几乎无法更新……, rejected: 梯度消失就是梯度变小可能产生一些影响。 }5.3 DPO 训练参数与典型坑DPO 训练我直接用了 TRL 库配置很简单from trl import DPOTrainer, DPOConfig dpo_config DPOConfig( beta0.1, lr5e-6, max_length1024, max_prompt_length512, ) trainer DPOTrainer( modelmodel, ref_modelref_model, train_datasetdataset, argsdpo_config, ) trainer.train()这里的 model 用 SFT 之后的学生模型初始化ref_model 必须是在相同 SFT 权重下冻结的副本。如果 ref_model 用错loss 的绝对数值会异常而且训练方向可能完全错误。β 常用 0.1可以先按这个值跑一个 epoch如果训练集 loss 在稳定下降说明数据分布和参考模型距离合理如果 loss 掉得极快但是生成质量变差说明 β 偏大改成 0.05 再试。学习率比 SFT 低很多1e-5 已经算上限。DPO 阶段最大的坑是 reward hacking。模型找到了提高 loss 的捷径表现为输出变得非常“谄媚”过度使用肯定语气和高频词汇但内容空洞甚至出错。应对方法很简单训练轮数限制在一个 epoch最多两个观测验证集上的人工评分而不是盯着 DPO loss 不放。DPO 不会给模型补充新知识它只改变模型对回答风格的偏好所以不要指望它对事实性错误有修复作用。5.4 蒸馏、PEFT 和 DPO 的组合路线完整的流程不是只能走一条直线可以自由组合。我在 Xihe 上实际跑了三条并行版本线第一条是全参 SFT 后直接 DPO用来观察对齐对全参模型的增益第二条是在 LoRA 适配器上做 SFT 和 DPO适合需要保留多套风格的部署场景第三条是蒸馏数据 SFT 后再 DPO这条线最终效果最好因为蒸馏已经提升了模型对高质量回答的模仿能力DPO 再进一步压缩偏好差距。路径选择没有绝对标准我建议按模块化看待预训练和 CPT 提供语言能力SFT 提供任务格式蒸馏提供更强的监督DPO 提供偏好约束。每一步都是可插拔的你完全可以在某个阶段单独停止或替换数据。6. 完整训练管线、显存省法与问题排查实录6.1 各阶段配置速查与成本总览把整个流水线放在一张表里看会更清楚阶段模型规模数据量学习率训练轮数/步数参考耗时8×4090预训练1.3B5B token1e-3 → 1e-4约 6000 步2-3 天CPT1.3B1B token 混合5e-5约 1000 步0.5 天SFT 全参1.3B1-3 万条2e-5 起1-2 epoch2-4 小时LoRA SFT1.3B同上1e-4 起1-2 epoch1-2 小时蒸馏 SFT1.3B2 万条生成数据2e-5 起1 epoch3-5 小时DPO1.3B8000 条偏好对5e-6 到 1e-51 epoch1-3 小时这个表只是我实验中的参考值不是标准答案。你的数据质量和机器配置不同数字会浮动很大但阶段之间的相对关系是稳定的SFT 和 DPO 的消耗远小于预训练所以把预算重点放在预训练和 CPT 上不会错。6.2 训练 NaN 与不收敛排查顺序这个可能是最多人卡住的问题。Loss 变成 NaN不要急着调学习率按顺序排查先检查数据里有没有空样本、控制字符、非法 token id其次检查 labels 是不是某个 batch 里全部为 -100这会让 loss 计算变成除零我实际就遇到过 SFT 阶段因为序列截断导致 loss 缺失的情况加上“有效 token 数小于 1 就跳过”的判断即可解决再检查混合精度FP16 容易溢出换 BF16最后看学习率和梯度裁剪梯度 norm 大于 10 时优先降学习率。Loss 不下降的排查思路不一样。如果预训练 loss 平着不降先确认数据是否真的切分并 shuffle 过我见过有人把同一个连续文本切片当成独立样本送进去数据顺序没打乱模型只能背顺序。其次检查 warmup 和峰值学习率是否匹配1e-3 对 1.3B 已经不小了如果还在大规模波动降一半重新跑。6.3 生成重复、空话连篇的常见原因生成重复这个问题在小模型和微调模型里特别常见。最直接的原因是训练数据里重复句子太多比如“好的请问还有什么可以帮您”在指令数据里出现几百次模型自然会把这句话变成高频模式。还有一种原因是 epoch 过多模型开始机械记忆训练集而不是学习泛化规则。我的经验是宁可把 epoch 减少到 0.5 epoch也不要跑到 3 个 epoch 以上。如果模型只是回答短、不会展开通常是数据里长答案不足。加一些长输出样本或者用大模型生成的蒸馏数据补充就能缓解。调解码参数对这种情况帮助有限那是治标不治本。6.4 显存不够的省钱方案小模型项目最常见的问题是“单卡放不下”。实际上 1.3B 模型在 24G 显存的 4090 上是能全参 SFT 的只要你把序列长度压到 512、开启梯度 checkpointing、使用 BF16 混合精度。如果显存还是不够有几个优先级很高的操作先把 batch size 降到最小用梯度累积补全局 batch再开 activation checkpointing代价是训练速度慢 20%-30%还可以做 4bit 量化走 QLoRA 路线。不到万不得已不要压缩序列长度因为序列长度直接影响模型对长上下文的建模能力。云 GPU 按小时租用也是一个好办法。预训练阶段租 8 卡 A100 或 H100 实例SFT 和 DPO 阶段直接用 4090 实例整体成本可能比买卡便宜很多。记得关实例我见过不少人忘了关导致费用翻倍。写在最后完整跑一遍的价值如果只追求从开源项目里拉一个模型下来跑推理你永远不会知道数据清洗在整条流水线里的分量也不会理解为什么 SFT 学习率要比预训练低两个数量级更不会明白 DPO 里的参考模型为什么必须冻结。这些知识不是看文档能补上的必须自己撞一次墙才能内化。我做完 Xihe 之后最大的体会是小模型从头训练难的不是某一个单独环节而是统筹一整条流水线。每个环节的决策都会传导到下一环预训练时偷懒不做去重SFT 时可能被重复数据带偏SFT 时多跑了几个 epochDPO 阶段可能怎么调都救不回来。如果你打算自己动手建议先用 0.5B 模型跑通全流程再把规模放大到 1.3B。等你完整跑完一次之后你再看“预训练模型下载”和“微调”这类话题视角会完全不一样。