从零开始理解大模型(六):训练——70 亿个参数是怎么"学"出来的

欢迎阅读「从零开始理解大模型」系列 —— 十篇文章,从"下一个词预测"到完整的大模型心智模型。每篇配可运行代码。
第一篇:一切从"猜下一个词"开始
第七篇:推理——你按下回车后的这一秒发生了什么
第八篇:上下文窗口——大模型的"工作记忆"
第九篇:Scaling Law——为什么"大力出奇迹"有效
第十篇:从大模型到 Agent——下一个词预测如何长出手脚
* 本系列配套运行代码,可在公众号后台回复“大模型”完整获取。
作者:十一
前五篇讲的是大模型的"身体结构"——Token、Embedding、Attention、FFN 怎么组装在一起。但结构只是骨架,参数才是灵魂。
一个刚初始化的模型,所有参数都是随机数。问它 "Thank you very" 后面是什么?完全瞎猜——50257 个 token 概率差不多。训练之后呢?99.2% 的概率输出 "much"。
从随机到精准,中间发生了什么?
▍一、先说结论

一句话版本:训练 = 喂数据 → 预测 → 算误差 → 调参数 → 重复几万亿次。
▍二、训练的核心循环
想象你在调一台有 70 亿个旋钮的收音机。目标是调到某个电台(让预测尽可能准),但你不知道每个旋钮该转到什么位置,只能靠试:
-
随便拧 —— 给所有旋钮一个随机初始位置 -
听一下 —— 用当前参数预测下一个词 -
对答案 —— 看预测和真实文本差多远(算 Loss) -
微调旋钮 —— 每个旋钮稍微转一下,方向是让差距变小 -
重复 —— 换下一段文本,再来一轮
重复几万亿次。每次只调一点点,但积累下来,70 亿个旋钮就逐渐到了正确的位置。
下面把每一步展开。
▍三、Loss——“猜得有多离谱”
模型输出 50257 个概率。训练时我们知道正确答案,所以可以量化"猜得有多差"——这个数叫 Loss(损失)。
3.1 具体例子
输入 "Thank you very",正确答案是 "much"。
随机初始化的模型 训练好的模型
"much" 的概率: 1/50257 ≈ 0.002% 0.992 (99.2%)
3.2 Loss 的计算公式
Loss = -log(P(正确答案))
代入数字:
随机模型: Loss = -log(1/50257) = 10.8 ← 很大,猜得很离谱
训练好的: Loss = -log(0.992) = 0.008 ← 接近 0,猜得很准
为什么用负对数?两个好处:
-
概率从 0 到 1,取负对数后变成 0 到正无穷——数值范围更适合做优化 -
猜得越离谱(概率越小),Loss 越大,惩罚力度和"离谱程度"成正比
你不需要记公式,只需记住:Loss 是一个数字,越小越好。训练的目标就是让它不断变小。
▍四、梯度——“每个旋钮该往哪边转”
知道了 Loss(猜得有多差),下一个问题是:70 亿个参数,每个该往哪个方向调?调多少?
4.1 梯度是什么
回到收音机。你现在 Loss 是 10.8(信号很差)。把某个旋钮稍微往右转一点点,听听 Loss 变了没:
-
变成 8.3 → 往右转是对的,继续 -
变成 8.7 → 方向反了,应该往左
梯度就是这个信号:告诉每个参数"往哪个方向调"以及"调多大步"。 数学上,梯度是 Loss 对每个参数的偏导数。但不需要理解偏导数——只要知道它给出了方向和幅度。
4.2 反向传播——从输出往回推
模型的计算方向是:
输入 → Embedding → Layer 1 → Layer 2 → ... → Layer 12 → 输出 → Loss
梯度的计算方向是反过来的:
Loss → 输出 → Layer 12 → ... → Layer 2 → Layer 1 → Embedding
从 Loss 出发,通过链式法则,把"该怎么调"的信号一路传回每一层的每一个参数。这叫反向传播(Backpropagation)。
就像多米诺骨牌倒着推——Loss 推倒最后一块,连锁反应一路传到第一块。每个参数都收到了自己该怎么调的信号。
4.3 梯度下降——一步一步走下山
有了梯度,就可以更新参数:
新参数 = 旧参数 - 学习率 × 梯度
学习率(learning rate) 是一个很小的数(比如 0.0001),控制每步走多远。太大会跨过最优解来回震荡,太小训练太慢。
整个过程就像在一个 70 亿维的山谷里找最低点:梯度告诉你哪边是下坡,学习率决定每步多远,一步一步走,最终走到(接近)谷底——也就是 Loss 最小的地方。
▍五、代码实验:亲手训练一个微型模型
GPT-2 太大,没法在笔记本上训练。附件 train_tiny.py[1] 实现了一个微型 Transformer——2 层、4 个头、128 维,在 10 句话上训练,CPU 几分钟跑完。
训练循环的核心只有四行,所有大模型的训练都是这四行:
# 1. 前向传播:用当前参数做预测
logits = model(x)
# 2. 算 Loss:预测和正确答案差多远
loss = F.cross_entropy(logits.view(-1, vocab_size), y.view(-1))
# 3. 反向传播:算出每个参数的梯度(该往哪调)
loss.backward()
# 4. 更新参数:沿梯度方向微调一步
optimizer.step()
不管模型有 10 万参数还是 1 万亿参数,训练循环都是这四步。差别只在每一步的计算量。
运行效果
Step 0: Loss = 83.250 (0.1s)
Step 50: Loss = 2.395 (0.5s) ████████████
Step 100: Loss = 1.767 (0.8s) ████████████████
Step 150: Loss = 1.311 (1.0s) ████████████████████
Step 200: Loss = 0.976 (1.3s) ██████████████████████
Step 250: Loss = 0.834 (1.7s) ███████████████████████
Step 300: Loss = 0.527 (2.0s) ██████████████████████████
Step 350: Loss = 0.312 (2.3s) ███████████████████████████
Step 400: Loss = 0.263 (2.6s) ████████████████████████████
Step 450: Loss = 0.264 (2.8s) ████████████████████████████
Step 499: Loss = 0.219 (3.1s) ████████████████████████████
训练后测试:
输入: 'The capital of ' → 输出: 'The capital of Italy is Rome.' ✓
输入: 'Thank you very' → 输出: 'Thank you very much for your help.' ✓
这说明了什么
Loss 从 83.250 降到 0.219——模型从瞎猜变成了能续写训练数据中的句子。前 100 步下降最快(容易的规律先学到),后面越来越慢(难的规律需要更多迭代)。
但它只是在"背课文"——我们只喂了 10 句话,模型记住了这 10 句话的模式。问它训练数据里没有的内容,它就会胡说。
真正的大模型在几万亿个 token 上训练,覆盖了互联网上的海量文本。所以它"记住"的不是具体句子,而是语言的统计规律——语法结构、事实知识、推理模式。数据量的差异,决定了"背课文"和"学会语言"的区别。
完整可运行代码见附件 train_tiny.py,纯 PyTorch 实现,不需要 transformers 库。
* 本系列配套运行代码,可在公众号后台回复“大模型”完整获取。
▍六、真实的大模型训练:三个阶段
我们的微型模型只经历了一个阶段。真实的大模型要经过三个阶段,每个阶段解决不同的问题。
6.1 预训练(Pre-training)——“广泛读书”
目标:让模型学会语言——语法、知识、推理能力。
数据:几万亿个 token 的互联网文本——网页、书籍、论文、代码、维基百科……
任务:就是我们讲过的"预测下一个词"。把文本切成片段,每个位置预测下一个 token,算 Loss,调参数。
规模感受:

预训练完成后,模型已经能生成流畅的文本,知道大量事实,能做简单推理。但它有个问题:不会好好回答问题。
你问它一个问题,它可能不回答,而是继续生成看起来像网页的内容——因为在训练数据里,一段文本后面跟的通常是另一段文本,不是"回答"。
6.2 SFT(监督微调)——“入职培训”
目标:教模型"好好回答问题"。
数据:人工编写的高质量问答对,通常几万到几十万条:
用户:法国的首都是哪里?
助手:法国的首都是巴黎。巴黎位于法国北部...
用户:写一个 Python 斐波那契函数
助手:def fibonacci(n):
if n <= 1: return n
return fibonacci(n-1) + fibonacci(n-2)
训练方式:和预训练完全一样——预测下一个 token,算 Loss,调参数。只是数据换成了对话格式,模型就学会了"看到问题后给出回答"的模式。
SFT 的数据量比预训练小得多(几万条 vs 几万亿 token),但它让模型从"续写机器"变成了"能回答问题的助手"。
6.3 RLHF(基于人类反馈的强化学习)——“师傅带徒弟”
目标:让回答更符合人类偏好——更有帮助、更安全、更诚实。
SFT 教模型"怎么回答",RLHF 教模型"什么样的回答更好"。
分两步做:
第一步:训练一个"打分模型"。同一个问题让模型生成两个回答 A 和 B,人类标注员选更好的那个。用大量这种偏好数据训练一个打分模型,让它能自动给回答打分。
第二步:用打分模型优化语言模型。模型生成回答 → 打分模型打分 → 分数作为奖励信号 → 调整参数让模型倾向于生成高分回答。
6.4 三阶段的效果变化
预训练前: "jk2#x..." ← 随机噪声
预训练后: "...the city is known for..." ← 流畅续写,但不会回答问题
SFT 后: "巴黎是法国的首都。" ← 能回答了,但质量参差不齐
RLHF 后: "法国的首都是巴黎。巴黎位于法国北部..." ← 回答详细、有帮助、安全

▍七、训练的工程挑战
原理不复杂,但真把一个 70B 模型训出来,工程上很难。
7.1 显存装不下
一个 7B 模型的训练需要多少显存?
参数本身: 7B × 4 字节 = 28 GB
梯度: 同样大小 = 28 GB
优化器状态: Adam 需要额外存两份 = 56 GB
激活值: 中间计算结果 = 数十 GB
──────────────────────────────
总计: 远超 100 GB
一张 A100 GPU 有 80 GB 显存,连参数和优化器都装不下——一张卡根本没法训 7B 模型。
解决办法是分布式训练:把模型切成几块,分到不同的 GPU 上,几千张 GPU 通过高速网络协同工作。这就是为什么训大模型要花数百万美元——大部分是算力成本。
7.2 数据质量比数据数量更重要
训练数据里如果充满错误信息、恶意内容或低质量文本,模型就会学到这些"坏习惯"。
所以训练前要做大量清洗:去重(互联网上到处是重复内容)、过滤垃圾页面、去除隐私信息、平衡语言和领域的比例。数据配比(多少英文、多少中文、多少代码、多少数学)是各家模型团队的核心秘方。
▍八、训练改变了什么
回顾前五篇,训练到底改变了哪些东西:
Embedding 表(第三篇):训练前是随机数。训练后,"France" 和 "Paris" 的向量变得接近,"国王 - 男人 + 女人 ≈ 女王" 自动形成。
Attention 的 Q/K/V 权重(第四篇):训练前,注意力分数是随机的,每个词对所有词的关注度差不多。训练后,"very" 学会了重点关注 "Thank you" 这个搭配。
FFN 的权重(第五篇):训练前,FFN 做的是随机变换。训练后,FFN 学会了存储和调用知识——看到 "Thank you very" 就激活 "much"。
所有这些变化,都来自同一个训练信号:预测下一个词。 没有人告诉模型 "France 的首都是 Paris",也没人告诉它 "Thank you very 后面接 much"。它只是在几万亿次预测中自动发现了这些规律,编码进了参数里。
▍九、结语
训练的本质简单得令人意外:预测 → 算误差 → 调参数 → 重复。
复杂的不是算法,而是规模——70 亿个参数、几万亿个 token、数千张 GPU、数月时间。把一个简单过程推到极致的规模,涌现出了看起来像"理解语言"的能力。
"Deep learning is just gradient descent on a loss function. Everything else is engineering."
深度学习就是在 Loss 上做梯度下降。剩下的全是工程。
下一篇,我们从训练切换到使用——你按下回车后的这一秒,模型内部发生了什么?为什么第一个字等得久、后面快了?KV Cache 是什么?
本文配套代码:train_tiny.py(微型 Transformer 从零训练)。纯 PyTorch 实现,不需要 transformers 库,CPU 几分钟跑完。

扫码回复“大模型”
获取本系列文章完整配套代码
「从零开始理解大模型」是「从零开始理解 Agent」的姊妹系列。Agent 系列讲"四肢",本系列讲"大脑"。建议对照阅读 专栏入口。
相关链接
今日推荐
关注AGENT魔方公众号,回复大模型
领取「从零开始理解大模型」实操配套代码
加速入门和掌握Agent:

- 点赞
- 收藏
- 关注作者
评论(0)