主题
第 12 章 微调与 GPT-2 基线:域差异如何影响比较
12.1 微调复用了哪一部分训练程序
在本仓库中,微调仍是下一 token 交叉熵训练,使用同一个 train.py、同一个 AdamW 和同一个因果模型。关键变化是从预训练权重开始、使用目标领域数据、通常采用更小学习率和更短日程。它没有新增 LoRA、指令模板、偏好优化或聊天角色机制。把原始戏剧文本微调成能续写戏剧,不能直接推成“训练了一个会遵循指令的助手”。微调配置
init_from='gpt2-xl' 导入的是权重,不是此前 GPT-2 训练的优化器状态。本地会新建 AdamW。init_from='resume' 才从本地 checkpoint 恢复优化器。这两种继续训练起点并不相同:一个保留参数知识、重新开始局部优化统计,另一个试图延续已有优化轨迹。
12.2 配置注释中的 epoch 是估算
微调配置设
最多 20 的设置按原停止条件会从 0 到 20 执行 21 次更新。每 5 步评估、仅在改善时保存,输出目录 out-shakespeare。学习率固定 decay_lr=False;模型为最大 GPT-2 型号,所以内存需求并不“小”。把迭代次数设少不能解决一次前向就放不下模型的问题。
缩小模型型号、微批次或 block_size 各有不同作用。换型号改变参数和初始知识;减小微批次主要减少激活,但可用累积补回全局 token 数;减小长度减少上下文与注意力成本,也改变学习任务。三种调整不能只比较“是否不再 OOM”。
12.3 基线要对齐数据域与 tokenizer
固定 README 报告了 OpenWebText 上的 GPT-2 基线:
| 型号 | 上游标注参数量 | 上游 train loss | 上游 val loss |
|---|---|---|---|
| gpt2 | 124M | 3.11 | 3.12 |
| gpt2-medium | 350M | 2.85 | 2.84 |
| gpt2-large | 774M | 2.66 | 2.67 |
| gpt2-xl | 1558M | 2.56 | 2.54 |
这是固定 README 的历史结果,未在本书 CPU 环境重新复现。四个 eval_gpt2*.py 文件分别指定型号,其他设置相同:批次 8、评估 500 批、eval_only=True、关闭在线日志。评估数据仍继承 train.py 默认 OWT。基线报告
为什么从头训练的 124M 模型报告约 2.85,而原 GPT-2 是约 3.12,不能立刻判定实现“比 GPT-2 强”?GPT-2 的原训练语料 WebText 未公开,OWT 是另一个尽力接近它的集合。模型直接在 OWT 上训练,天然适应该分布;原权重未经适应就评估,比较包含数据域差异。README 还报告把 GPT-2 权重在 OWT 上继续训练后也能接近 2.85,因此更合理的比较应把这种适应机会考虑进去。
即使验证损失相同,也不保证生成风格、事实正确率、长文一致性或下游任务相同。交叉熵只评价给定数据上真实下一个 token 的概率。改变 tokenizer 后,单 token loss 更不能直接比较:字符一个位置与 BPE 一个位置携带的信息量不同。若一定跨 tokenizer 比较,需要定义共同单位,例如按原始字节归一化的负对数似然,并认真处理编码边界。
12.4 小数据微调的失败方式
验证越来越差而训练越来越好,可能意味着过拟合,也可能暴露训练与验证分布差异。只看训练 loss 选择 checkpoint 会奖励记忆训练集。原配置采用验证改善保存是一种基本保护,但随机窗口验证有噪声,频繁比较也会增加挑中偶然好结果的机会。
提示编码错配会让微调无效,即使 loss 在下降;第 2 章已说明必须保持预训练 token 身份。过高学习率可能迅速破坏预训练表示,过低则在少数更新内几乎不改变。较大 dropout 也不是无条件更好,尤其原配置实际上未启用它。可信调参应先固定数据和验证方法,每次只改变清楚定义的因素,记录结果和资源成本。
本书没有运行 GPT-2 微调,不提供捏造的最佳学习率或训练时长。合成小模型的恢复实验只能验证通用状态流,不能替代加载预训练权重、领域适应和大模型内存测试。
补充练习。 模型 A 在字符编码验证集上 loss=1.5,模型 B 在 BPE 验证集上 loss=2.5,A 一定更好吗?
答案。 不能这样排序。它们预测单位不同,还要确认原始文本、切分、上下文覆盖、归一化和评估协议。即使将两者都指数化为 perplexity,单位差异也不会消失。