第 28 章 大语言模型怎样训练出来
文章目录
- [第 28 章 大语言模型怎样训练出来](#第 28 章 大语言模型怎样训练出来)
-
- [🌈 关于《AI 零基础 36 讲》](#🌈 关于《AI 零基础 36 讲》)
- 从资料到训练样本,还隔着哪些工作
- 预训练得到续写能力,任务要求还要单独学习
- 只对回复计算损失,具体遮住哪几格
- 偏好记录怎样改变训练目标
- 参数固定以后,温度改变什么
- [固定模型的 49 次生成怎样比较](#固定模型的 49 次生成怎样比较)
- 怎样确认没有偷偷训练
- 上下文和资源限制从哪里来
上一章的小模型训练 300 次后,能沿着已有前缀续写。现在要分清两件事,模型参数是怎样得到的,以及参数固定以后,程序怎样选择输出。把温度从 1 改成 2,不等于重新训练;输入一条要求,也不会自动把它写进模型参数。
本章说明语料准备、预训练、指令微调、偏好优化和推理的关系,再复用第 27 章的固定模型进行 49 次生成。你会看到较高温度出现不通顺文字,也会看到两组不同温度恰好产生相同统计。前置依赖为第 27 章,本章代码见GitHub仓库。

🌈 关于《AI 零基础 36 讲》
🧠 零基础也能开始学 AI
《AI 零基础 36 讲》是一套面向初学者的 AI 入门教程。课程从认识和使用 AI 开始,逐步学习
Python、数据处理、机器学习与深度学习,再进入大模型应用开发,最后完成个人知识库助手的综合实践。
📖 本篇是正式讲解文章
通过具体例子、原创图示和操作结果讲清概念。涉及编程的章节提供可运行代码,方便你边读边试。
🎯 读完以后,动手检验
建议按专栏顺序学习,并完成对应的课后训练,检查自己能否独立运用本章知识。
博客专栏:《AI 零基础 36 讲》
从资料到训练样本,还隔着哪些工作
自回归语言模型的预训练通常把文本转换成 Token 序列,用此前内容预测下一 Token。第 27 章的移位输入与目标就是缩小的例子。大量文本能提供多种词语、句式和上下文关系,但数量增加不能代替数据质量检查。
准备语料时,先要记录来源与使用许可,排查不应进入训练的私人信息,再进行格式处理、质量过滤、重复识别和数据划分。若一段内容反复出现,它对训练的影响可能被放大;若测试内容混入训练,测到的成绩也可能过于乐观。公开文本能被访问,不表示任何用途都无需核对许可。
本专栏的第 27 章语料有十二条自行编制的短句,没有外部来源问题,但范围非常窄。它没有提供正式的训练测试划分,因此我们一直把成绩称为训练损失。把同一组"小猫吃鱼。"等句子多复制一万次,记录条数变多了,表达方式和知识范围仍没有增加。
本章固定复制上一章模型,保存快照来源与哈希。实验读这个副本,不重新训练,也不修改第 27 章文件。
预训练得到续写能力,任务要求还要单独学习
在下一 Token 目标下,文本自身提供后续目标,不需要人为为每个位置写一条问答标签。预训练更新模型参数,使它在训练分布上减少预测损失。通过广泛语言数据学习的模型可以用于多种后续任务,GPT-3 的研究也是这一类路线的代表。
本章小模型在"小猫"后保留"吃"和"喝"两个分支,它学的是已有短句的续写规律。若向它提问"给我一个学习计划",词表甚至没有覆盖全部字。它无法仅凭一次提示,就获得完整的问答能力。
指令微调常用"要求与示范回答"数据,继续更新已有模型。比如本章原创教学记录中,要求是"给我一个20分钟读书计划",示范回答为阅读 10 分钟、摘记 8 分钟、回顾 2 分钟。数据还可以说明回答格式、篇幅与约束,帮助模型学习怎样按任务组织输出。
这些教学记录只是数据格式示意,本章没有用它们执行微调,也没有把小模型改造成计划助手。对于实际训练,还需明确聊天格式、目标 Token 的范围、优化设置和评估方法。
只对回复计算损失,具体遮住哪几格
用已有词表做一个更小的完成式例子,提示为"我学",回复为"编程。"。前缀和回复合起来形成"我学编程。",网络依然预测下一 Token。我们可以只保留回复和结束标记的目标,把预测提示文字的两个位置排除。
text
输入 BOS 我 学 编 程 。
目标 我 学 编 程 。 EOS
回复目标 忽略 忽略 编 程 。 EOS
python
from examples.training_core import load_baseline, response_only_mask
model, tokenizer = load_baseline()
x, targets = response_only_mask(tokenizer, "我学", "编程。")
print(x.shape)
print(targets.tolist())
print(int((targets != -100).sum()))
输入形状为 (1,6),目标前两项为 -100,实际保留四项。完整目标编号在实验结果中。计算这些目标的损失约为 0.001695,但程序没有调用反向传播或优化器,因此这只核对了目标掩码,不是一次完成的微调。
回复目标掩码与因果注意力掩码也有不同用途。前者决定哪些目标参加损失,后者决定一个位置能读取哪些位置的信息。把提示目标忽略以后,回复仍需要读取提示,不能因此把全部提示内容从注意力中屏蔽。
偏好记录怎样改变训练目标
只有示范答案时,程序知道应当模仿什么;加入比较记录后,还能表达同一问题下更偏向哪种回答。我们为"20分钟读书计划"准备两份教学候选,第一份合计 20 分钟,第二份合计 90 分钟。按"满足总时长"的明确标准,第一份被标作 chosen,第二份为 rejected。
python
from examples.training_core import load_teaching
pair = load_teaching()["preference_pair"]
for name in ["chosen", "rejected"]:
print(name, sum(item["minutes"] for item in pair[name]))
结果为 chosen 20 和 rejected 90。这是一条可检查的教学标准,没有开展真实用户评分,也没有获得模型评审记录。更复杂的偏好还涉及准确性、清晰度、约束遵守等维度,不能只凭表达更长或语气更肯定就判好。
一种路线先训练奖励模型来估计偏好,再把这个估计作为进一步优化的信号;另一种路线如 DPO,可以直接使用偏好对进行优化,无需把所有后训练都组织成同样的奖励模型加强化学习过程。
偏好优化让模型更倾向训练标准认可的行为,但评分来源和标准本身也需要验证。更符合偏好不等于每个事实自动变真,训练后仍要做独立的行为与任务评估。下图概括常见阶段,实际流程可以重复进行多轮,并增加其他训练和评估步骤。

本章执行的是图末端的推理实验,固定模型只经历了上一章的教学下一 Token 训练,尚未经过指令或偏好训练。
参数固定以后,温度改变什么
推理读取已有参数,针对当前输入计算词表分数。温度在抽样前把分数除以一个正数,再做 Softmax。较低温度放大分数差,较高温度使分配更平缓。相关生成方式见 Hugging Face 生成策略说明,本章直接在 PyTorch 中实现缩小计算。
先用原创分数 [2,1,0] 排除模型其他部分的影响。三种温度实际计算如下。
| 温度 | 候选 A | 候选 B | 候选 C |
|---|---|---|---|
| 0.5 | 约 0.866813 | 约 0.117310 | 约 0.015876 |
| 1 | 约 0.665241 | 约 0.244728 | 约 0.090031 |
| 2 | 约 0.506480 | 约 0.307196 | 约 0.186324 |

python
from examples.training_core import probabilities_at_temperature
for temperature in [.5, 1, 2]:
p = probabilities_at_temperature([2, 1, 0], temperature)
print(temperature, p.numpy().round(6))
候选 A 始终最大。温度提高改变的是抽到各候选的机会,不能从这张表推断 B、C 的内容是否正确、是否有创造性。较低温度也不能把已经排第一的错误答案自动改对。
贪心选择只取最高分,正温度通常不改变这些候选的排序,所以在本章纯贪心实现中,仅改温度不会改变所选 Token。要观察温度带来的随机选择变化,还要启用抽样。
固定模型的 49 次生成怎样比较
所有组使用同一份模型、同一个"小猫"提示和最多 12 个新 Token。抽样组分别用种子 0 至 11 运行,每个组都保留十二条输出。还有一条温度 2 的贪心对照,共 49 条。每组换回相同种子列表,避免结果只展示某一次碰巧好看的回答。
| 设置 | 次数 | 不同文本数 | 输出记录 |
|---|---|---|---|
| 温度 0.5 抽样 | 12 | 2 | 吃鱼 7 次,喝水 5 次 |
| 温度 1 抽样 | 12 | 2 | 吃鱼 7 次,喝水 5 次 |
| 温度 2 抽样 | 12 | 6 | 多个偏离短句模式的结果 |
| 温度 2、top-k 为 2 | 12 | 2 | 吃鱼 7 次,喝水 5 次 |
| 温度 2 贪心 | 1 | 1 | 小猫吃鱼。 |
温度 0.5 与 1 恰好给出同样统计,这在小样本、接近二选一的分配里完全可能。本次十二次抽样不能证明这两个温度的整个概率分布相同。温度 2 的输出增加到六种,其中包括"小猫吃读。"、"小猫吃鱼我"和"小猫吃鱼。练今天。",它们都属于实际失败记录,没有删掉。
这些结果说明,本次提高温度使小模型更容易选到低分候选,也产生了不通顺续写。不同文本数增加,不等于质量提高。十二条抽样规模很小,无法据此写出所有模型的最佳温度。
top-k 为 2 表示每一步只保留当时分数最高的两个候选,再在它们之间重新分配和抽样。这不是在最初选两条完整句子,也不保证两项一定是真实或合适的内容。它在本次温度 2 实验中减少了低分字符进入续写的机会,得到两种已有短句。
结果保存在逐条 CSV和带全部逐 Token 信息的JSON。
怎样确认没有偷偷训练
实验开始前复制模型全部参数,结束后逐值比较;模型状态均保持一致。固定权重文件在实验前后也核对 SHA-256,一致。程序使用 eval() 和 no_grad(),没有创建优化器或执行参数更新。
python
import json
from pathlib import Path
result = json.loads(Path("results/parameter-summary.json").read_text(encoding="utf-8"))
print(result["parameters_unchanged"], result["baseline_file_unchanged"])
print(result["instruction_training_done"], result["preference_training_done"])
输出为 True True 和 False False。这使"推理参数变化"和"模型参数学习"有可以复核的边界。在普通对话里给模型补充资料,是改变本次输入上下文;是否进入未来训练,是另一个需要根据实际产品和配置核对的问题。
上下文和资源限制从哪里来
本章模型最大 16 个位置,BOS、提示和续写共同占用这个长度。生成还会检查新 Token 上限,不能要求任意长的输入和输出。
资源不仅是参数文件。一个假定有十亿个 float32 参数的模型,仅这些数值就占约 40 亿字节,即十进制 4 GB;这还没有计入梯度、优化器状态、中间激活和推理缓存。这里是字节数量的教学计算,并非某个产品的实际显存要求。训练通常比只保存权重需要更多资源,生成更长输入和输出也可能增加运行时间与缓存需求。
第 27 章的小模型只有 3535 个参数,才能在普通 CPU 上迅速演示整个循环。把它做大还涉及更多数据、计算与评估工作,不能只改一个层数就声称复现了大型系统。
常见报错中,本章不允许温度为 0,因为代码执行分数除以温度;要确定性选择就用贪心模式。另一个错误是 top-k 超过有效词表候选数,修复版改为 2。
完成【零基础学AI】第 28 章课后练习与答案,试着从结果文件指出哪一步改变了数据、哪一步改变了模型参数、哪一步只改变选择方式。下一章会把本地调用换成 API 请求,让程序处理配置、响应、用量和常见失败。