English interface selected · this article is currently written in Chinese.
怎样完成一个可解释的预训练实验:基线、日志与恢复验证
English overview →具备清晰骨架、初步数学推导或工程验证,持续补充论据与实测。
数字花园
🌿 什么是数字花园与思想演进?
遵循 Maggie Appleton 与 Andy Matuschak 的常青笔记理念:这里不是按时间沉底的流水账,而是持续修剪打磨的知识生态。文章按成熟度经历:
- 🌱 萌芽 (Seedling): 发散灵感、读书摘录、开放猜想
- 🌿 演进 (Budding): 结构渐明、初步代码推导、积极修正
- 🌳 常青 (Evergreen): 逻辑闭环、持久经得起检验的基石
- 🔬 实验待证 (Speculative): 结合沙盒与仿真探针的理论探索
现在我们已经知道,文本如何变成 token,模型怎样读取上下文,损失怎样计算,以及一次参数更新包含哪些步骤。
接下来的诱惑是直接选择一个更大的模型,让它训练一晚上,第二天看结果。问题是,如果结果不好,我们可能仍然不知道是数据、代码、预算还是模型规模造成的。
一个好的起步实验,不是一次把所有事情做大,而是让每一步都能回答一个清楚的问题。 本篇把前五篇整理成实验顺序,同时说明每一阶段能支持什么结论。
下文的完整实验方案尚未作为一组正式研究对照执行。仓库已有的短程工程记录会单独说明,不与方案中的预期混写。
先写一句能被结果否定的问题
“训练一个好模型”太宽,无法决定下一步该看什么。“验证这套代码是否真的更新参数”则明确得多。
第一轮可以分成四级:
| 阶段 | 要回答的问题 | 通过后还不能说明什么 |
|---|---|---|
| 工程冒烟 | 能否完成读取、反向、保存和加载 | 模型学会了语言 |
| 极小样本拟合 | 能否学会固定的几条记录 | 对新文本有效 |
| 保留集比较 | 未见数据的预测是否改善 | 实际任务已满足要求 |
| 任务检查 | 指定任务和条件下是否更好 | 所有能力都改善 |
先排除低层错误,再投入更大预算。四级不是四个漂亮标签,而是不同的证据要求。训练循环正常退出,只能证明其中非常有限的一部分。
对于第一卷的中文技术语料场景,一个后续研究问题可以是:在固定原始文档和有效目标预算下,某项清洗改动是否改善中文技术验证文本的预测,同时不明显损害英文部分?
这句话包含改动、预算和分项结果,比“清洗后效果更好”具体。但正式比较之前,训练流程本身需要通过前面两级检查。
把一次运行的输入固定下来
第一卷保存的数据记录,在这里要与模型配置连接。
至少保存数据版本和划分、分词器文件与编号映射、模型结构和初始化方式、上下文长度、打包与标签规则、优化器和调度,以及软件与设备信息。只保存一份权重,之后很难知道它是怎样得到的。
对照实验还需要区分“固定”和“相同”:两个配置文件看起来相同,数据顺序可能不同;文件路径相同,内容可能已经被改写。对重要输入保存内容校验值,可以帮助发现这些变化,但校验值相同本身不证明数据设计合理。
可以用下面的简短记录开始,不需要先造一个复杂平台:
| 字段 | 示例中的含义 |
|---|---|
| 研究问题 | 只改变一项清洗规则,比较保留集预测 |
| 数据身份 | 训练、验证、测试清单及内容校验值 |
| 目标定义 | 因果预测、有效标签规则、token 平均 |
| 固定项 | 初始化、分词器、模型、预算、评价过程 |
| 改变项 | 这次要检验的清洗规则 |
| 失败判据 | 非有限损失、恢复不一致、验证输入重叠 |
| 结论范围 | 当前数据、预算和模型下的观察 |
例子中的清洗研究只是后续候选问题。最初检查训练代码时,保持数据不变,不要同时引入这个变量。
第一关:一批数据能否走完整个计算过程
先取很小的一批,完成以下链条:
文档 → token → 输入与标签 → logits → 损失 → 反向传播 → 参数更新 → 保存 → 新进程加载每个箭头都有可检查的对象。分词后检查还原与长度;目标对齐时逐项查看前缀和标签;前向计算检查形状及因果性;损失检查有效数与有限值;更新前后比较可训练参数是否真的发生变化。
参数变化不代表方向正确。若希望进一步检查,可以用一个固定小例子,对照独立手算的损失或梯度方向。第二篇的三个候选分数就适合这种用途。
保存后不要只在同一进程里读取。开一个干净进程,从磁盘恢复配置、分词器和权重,再对固定输入计算输出,可以发现进程里残留对象掩盖的问题。
第二关:小到可以记住的数据能否被拟合
取两三条短文本,反复训练。这里的目标就是有意让模型记住少量数据,因此不能再拿这些样本上的改善宣称泛化。
观察训练损失是否显著降低,同时检查原有目标没有被改写。若只是把困难位置从 loss mask 中删掉,平均损失也可能更低,却不是模型更会预测了。
这一关失败时,优先检查参数是否包含在优化器中、梯度是否被断开、有效目标是否为零、标签是否错位,以及学习率是否合适。先不要用换数据集来掩盖问题。
通过后,也不要求采样必须每次完整复述原文。采样策略会引入变化,EOS 和上下文边界也会影响结果。固定条件下的目标概率、损失和确定性输出,可以提供更容易解释的检查;正式生成质量另行评价。
第三关:保留集是否真的在改善
正式训练前,固定一份不参与参数更新的验证集。验证时仍然使用相同的分词、标签和上下文约定,并明确模型的评估模式。
把各批次有效损失总和加起来,再除以有效目标总数,避免不同长度的 batch 被错误等权平均。中文说明、英文材料和代码最好分别报告,防止整体均值掩盖某一类退化。
假设出现下面三种曲线,应作不同解释:
| 训练表现 | 验证表现 | 应追问什么 |
|---|---|---|
| 训练损失降低 | 验证损失也降低 | 是否来自重复或泄漏;幅度是否超过运行波动;各类是否一致 |
| 训练改善 | 验证不变或变差 | 是否过拟合、分布差异或目标错配 |
| 训练也不改善 | 验证也不改善 | 优化是否正常、预算是否足够、输入是否异常 |
这张表给的是诊断方向,不是自动判因。比如训练与验证存在分布差异时,二者绝对值未必具有直接大小关系。
验证集可以用于选择配置,但反复选择会让研究过程逐渐适应它。最终想报告较可信的泛化结果,还应保留不参与这些选择的测试集,并说明尝试过多少设置。不要把最有利的一次随机运行当成稳定结论。
生成样本帮助定位问题,不替代固定评价
每次保存检查点时,可以用一组固定提示生成文本,记录完整输出和生成参数。这样能观察结束、重复、格式和局部语言现象。
但不要只展示最漂亮的三段。提示如果经过反复挑选,读者看见的是筛选后的展示,而非模型的平均行为。
对尚未做指令微调的基础模型,也不应仅用聊天格式提问,然后把“不像助手一样回答”判定为预训练失败。可以先采用与续写任务一致的提示,再把指令遵循留给第三卷专门研究。
对于技术内容,文本流畅与事实正确是两项指标。若没有人工核对或可执行验证,就不把一个看似专业的段落记为知识正确。
成本至少同时看 token 和时间
比较两个方案时,固定更新步数往往不够。有效 batch 不同,一步处理的目标就不同;分词器不同,相同 token 数又可能对应不同原始文本量。
因此,运行记录应同时保留累计输入位置、非填充内容、有效目标、优化器更新次数和墙钟时间。需要比较效率时,明确分子与计时范围。
例如假设一轮测量处理 12,000 个有效目标,用时 30 秒,那么有效目标吞吐为每秒 400。若其中 10 秒是首次编译或准备,后续稳定训练可能不同;这两个时间口径应该分别报告,不能只删掉不利部分。
峰值内存也要说明测量工具。某一时点的已分配内存不是全过程峰值;进程生命周期的最高常驻内存,也不是当前阶段独占使用量。在统一内存设备上,更不能随意把几个来源的读数相加。
短跑能帮助估计是否值得继续,但不足以推算长时间热状态、交换或数据加载瓶颈。扩大规模前应重新测量,不能把小模型的每秒 token 简单按参数量外推。
恢复训练要恢复的是过程,不只是权重
设训练在第 100 次更新后中断。重新加载模型权重,再用一个全新优化器继续,并不等于接着第 101 次更新走。
AdamW 的历史状态、调度位置、混合精度缩放状态以及数据读取位置都可能影响下一步。随机数状态还会影响 dropout、采样和顺序。PyTorch 的检查点教程明确指出,用于恢复训练的保存内容应包含优化器状态,而不只是模型参数。保存与恢复教程
一个更完整的检查点需要根据实际流程记录:
- 模型、优化器、调度器和适用时的梯度缩放状态。
- 已完成更新、已消费目标数、数据排列与读取位置。
- 使用到的随机数生成器状态。
- 配置、代码和数据版本,以及保存边界。
最好先在参数更新完成的边界保存。如果在梯度累积到一半时保存,却没有保留已累积梯度和对应计数,恢复后就不能声称与未中断过程相同。
流式数据还有预取、缓冲和重复读取问题。只记“已经读了多少行”不一定足以恢复完全相同的下一批样本。
用两条分支验证恢复
从同一个初始状态出发,安排两次短运行:
- A 连续运行 次更新。
- B 运行 次后保存,结束进程,再加载并运行 次。
比较恢复后的数据批次、学习率、损失、参数和必要优化器状态,而不只是最后生成的一句话。若数据批次已经不同,应先修复读取状态,不能直接把差异归咎于浮点误差。
在确定性设置及相同环境中可以要求很严格的一致性;但 PyTorch 说明,不同版本、平台或设备之间不能普遍保证完全复现。随机种子相同也不是充分条件。PyTorch 复现说明
跨设备比较时,要事先定义合理容差和任务层面的验收,而不是看到逐位不同就判定恢复失败,也不能把任何大差异都用“浮点误差”带过。
仓库已有的证据支持到哪一步
本站仓库已有一个小模型项目,包含随机初始化 decoder、预训练、SFT、DPO、检查点和本地生成流程。可以从训练工作台进入相关内容。
归档的 2026-10-04 验证记录报告了 138,560 参数模型的短程工程运行:预训练 12 步、SFT 8 步、DPO 8 步,并恢复预训练至第 14 步。这里引用的是已有记录,不是本篇重新运行的实验。项目验证记录
那份记录的输入是少量合成 fixture,目的在于验证反向传播、目标遮罩、保存恢复和跨阶段接口。它没有证明 30M 模型已完成正式训练,更没有证明从零训练的小模型已经具备可靠助手能力。
已有骨架也有范围限制,例如文档独立分块与完整的流式 packing 不是同一件事,常量学习率也不等于本文讨论的各种调度方案都已实现。使用它做实验时,要根据实际源码确认支持什么。
这类记录仍然有价值:它让后续工作不必从“程序能不能跑”重新开始。但下一阶段必须补充真实数据、持续资源测量和独立评价,而不是把短跑数字包装成模型能力报告。
一份实验报告应该让别人能复核什么
报告不必很长,但至少回答五个问题:改了什么,固定了什么,实际运行了什么,结果是什么,哪些解释还不能排除。
若一次改动的验证损失改善很小,先检查重复运行的波动和有效 token 口径;若任务分数提升却耗时翻倍,就把收益和成本同时报告。若失败,保留失败条件和日志位置,它们可能比一个没有边界的“推荐配置”更有用。
最终结论可以很有限,例如:“在这份固定数据、预算和三次初始化下,改动 A 的中文验证损失更低,但英文差异不稳定;尚未测试更长上下文。”这种表达足够有信息,不必升级成“全面提升模型能力”。
第二卷到这里建立的是一套能解释训练过程的基础。后续 SFT 可以直接选择已有基础能力的开放权重模型,不必等待自制小模型长成通用助手;关键是继续保留这里建立的数据、目标和评价约定。
两个检查理解的问题
第一,一个模型能拟合三条文本,保存后也能生成相同句子。它已经通过了哪些检查?还缺什么证据,才能说对新技术文本有改善?
第二,连续训练与恢复训练的结果不同。请按数据批次、状态恢复、随机性和数值实现的顺序,设计一个能逐步缩小原因范围的检查过程。
文章概念网络
从章节进入正文概念。实线表示所属层级,虚线连接跨章节重复出现的概念,不代表因果关系。
71 / 71 个节点 · 正文标记术语与关键词概念
怎样完成一个可解释的预训练实验:基线、日志与恢复验证
回到原文 ↗最后更新于 2026-10-20
引用本文
@article{2026-10-20-llm-training-pretrain-06-experiment,
author = {枫语},
title = {怎样完成一个可解释的预训练实验:基线、日志与恢复验证},
journal = {枫语},
year = {2026},
month = {oct},
url = {https://meiluosi.github.io/posts/2026-10-20-llm-training-pretrain-06-experiment/}
}