养过龙虾的人都知道,决定龙虾能力的还是
VibeCoding的人都知道,决定代码质量的还是大模型。Opus模型可以全托管,其它模型只能扶着走,有的模型根本付不起来。
大家的工作和生活都越来越离不开大模型了,那么你有没有想过自己来训练一个模型,自己来训练一个有推理能力的模型,自己来训练一个举一反三的模型。
有人会说了,训练模型都要钱,都要名校毕业,都要硕士都要博士,这些都只有大厂能搞出来,最先进的模型只有美丽国才能搞出来。
其实不完全是这样的。我们也可以的,只使用家里的电脑就可以。
下面我带小伙伴手搓代码用家用电脑来训练一个小模型。本次先从原理讲起,然后进行实践。
在讲之前,先看下效果:




在开始之前,先看看整个学习路径,心中有数:
📍 第1步:理解AI模型是什么(10分钟)
↓
📍 第2步:认识模型的核心组件(15分钟)
↓
📍 第3步:了解训练是如何进行的(15分钟)
↓
📍 第4步:动手训练自己的模型(5分钟)
↓
📍 第5步:测试和验证效果(5分钟)预计时间:50分钟(实际训练只需要11.5秒)
前置知识:不需要任何编程或数学背景,会使用电脑即可
学习方式:先理解概念,再看代码,最后动手实践
学习技巧:
你是否想过:我也能训练一个会对话的AI吗?
答案是肯定的!这篇文章将手把手带你从零开始,用最简单的方式理解AI训练的原理,并在1小时内(实际上只需要11.5秒)训练出属于你的第一个AI模型。
不需要昂贵的GPU,不需要深厚的数学背景,只需要一台普通电脑和一颗好奇的心。
方式1:从头到尾阅读(推荐)
方式2:按需阅读
每个章节都包含:
遇到不懂的地方怎么办?
什么时候动手实践?
如何检验学习效果?
✅ 理解什么是AI模型 ✅ 知道模型训练的基本概念 ✅ 了解小模型的优势
想象你在教一个小学生学习乘法:
传统教学方式:
AI训练方式:
举个例子:
给AI看这些例题:
2 × 3 = 6
4 × 5 = 20
7 × 8 = 56
...AI会"思考":哦!原来乘法就是重复相加!
这就是训练的核心:从例子中学习规律。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
让我们用最通俗的方式理解几个核心概念:
就像学生学习需要课本,AI学习也需要数据
我们的数据示例:
问题:"什么是注意力机制?"
答案:"注意力让模型关注重点。"就像学生用大脑思考,AI用模型处理信息
我们的模型:
- 大小:337万个参数(像337万个脑细胞连接)
- 类型:GPT(一种专门处理文本的模型)
- 能力:理解和生成中文就像学生通过做题来学习,AI通过训练来改进
训练过程:
1. 给AI一个问题
2. AI尝试回答
3. 对比正确答案
4. 根据错误调整自己
5. 重复这个过程就像学生脑中的知识网络,AI有参数
参数的作用:
- 存储学到的规律
- 决定模型的能力
- 训练就是调整这些参数
我们的模型有337万个参数:
- 看起来很多
- 实际上很小(GPT-3有1750亿个)
- 小模型训练快,易理解就像学生用学到的知识考试,AI用训练好的模型回答问题
推理过程:
1. 给模型一个问题
2. 模型根据训练结果预测答案
3. 输出预测的文本GPT = Generative Pre-trained Transformer
让我们拆解这三个词:
含义:能够生成新的内容
例子:
输入:"北京是中国的"
输出:"首都"(补全句子)
输入:"写一首关于春天的诗"
输出:"春风吹绿柳枝头,桃花满园笑颜流..."为什么选择生成式模型?
含义:先在大规模数据上训练基础能力
类比:
小学教育:
1. 先学基础知识(识字、算术)
2. 再学专业知识(历史、地理)
AI训练:
1. 预训练:学习语言基础(在大规模文本上)
2. 微调:学习特定任务(在我们的数据上)
我们的模型:
- 直接从零训练(相当于小学从头学起)
- 数据量小但质量高(精品教育)
- 时间短(11.5秒,超快速)为什么从零开始?
为什么选择Transformer?
我们的模型只有3.37M(337万)个参数,对比一下:
模型 | 参数量 | 训练时间 | 计算资源 |
|---|---|---|---|
我们的模型 | 337万 | 11.5秒 | 普通CPU |
GPT-2 | 15亿 | 数周 | 数百GPU |
GPT-3 | 1750亿 | 数月 | 数千GPU |
小模型的好处:
什么时候用大模型?
什么时候用小模型?
训练一个能够回答简单问题的AI助手,比如:
用户:什么是注意力机制?
AI:注意力让模型关注重点。
用户:如何让模型关注重点?
AI:使用注意力机制。
用户:为什么需要注意力?
AI:为了让模型理解重要信息。这看起来简单,但背后蕴含了AI训练的核心原理:
✅ 如何让计算机理解文本 ✅ 如何让模型学习规律 ✅ 如何优化训练过程 ✅ 如何生成合理的回答
学完这一章,你应该能够:
📖 第一章学习总结
核心概念回顾:
关键要点:
✅ AI训练的核心是"从例子中学习规律"
✅ 小模型训练快、资源要求低、易于理解
✅ GPT是生成式、预训练、Transformer架构的模型
✅ 训练数据的质量比数量更重要
下一步学习:
自我评估:
如果以上问题的答案都是"是",恭喜你!你已经准备好进入下一章了!🎉
✅ 理解模型如何处理文本 ✅ 认识注意力机制的作用 ✅ 了解位置编码的必要性 ✅ 知道模型的基本结构
📍 2.1 文本处理(基础)
↓
📍 2.2 注意力机制(核心)
↓
📍 2.3 位置编码(补充)
↓
📍 2.4 模型架构(整体)前置知识:理解了第一章的AI模型基本概念
人类理解文本:
看到"苹果"这个词:
- 脑中浮现苹果的图像
- 知道它是水果
- 知道它的味道、颜色计算机理解文本:
看到"苹果"这个词:
- 只是一串字符:'苹' '果'
- 计算机不认识中文
- 只能处理数字解决方案:把文本转换成数字
方法:给每个字符分配一个数字ID
字符 → 数字ID映射表:
'苹' → 12345
'果' → 12346
'注' → 12347
'意' → 12348
'力' → 12349
'机' → 12350
'制' → 12351
'。' → 12352
...例子:
文本:"苹果"
数字:[12345, 12346]
文本:"注意力机制。"
数字:[12347, 12348, 12349, 12350, 12351, 12352]问题:数字ID之间没有关系
方法:把每个字符转换成一个向量(一组数字)
字符 → 向量映射:
'苹' → [0.1, 0.3, -0.2, 0.5, ...]
'果' → [0.2, 0.1, 0.4, -0.1, ...]
'注' → [-0.3, 0.5, 0.1, 0.2, ...]
...向量的含义:
例子:
'苹'的向量:[0.9, 0.1, 0.0, ...]
'果'的向量:[0.8, 0.2, 0.1, ...]
'注'的向量:[0.1, 0.9, 0.0, ...]计算相似度:
'苹'和'果':很相似(经常一起出现)
'苹'和'注':不相似(没有关系)为什么用向量?
捕捉语义关系
"苹果"的向量 + "橙子"的向量 ≈ "水果"的向量
相似的词,向量会接近便于计算
计算机可以计算:
- 两个词有多相似(向量距离)
- 一个词和另一个词的关系(向量运算)压缩信息
一个词的丰富含义被压缩到一个向量中
包含:语义、语法、用法等多方面信息问题:文本是有顺序的
"我爱你" vs "你爱我" vs "爱你我"
同样的字,顺序不同,意思完全不同解决方案:把一个句子的所有字按顺序输入模型
句子:"注意力机制"
序列:['注', '意', '力', '机', '制']
向量:[v1, v2, v3, v4, v5]
模型按顺序处理:
v1 → v2 → v3 → v4 → v5关键点:
人类的注意力:
读这句话:"小明吃了苹果,因为苹果很好吃。"
当你读到第二个"苹果"时:
- 你的注意力会自动关注第一个"苹果"
- 你知道两个"苹果"是同一个东西
- 你理解了这句话的意思AI的注意力:
模型处理这句话:
- 当处理"苹果"这个词时
- 也会关注句子中的其他词
- 计算每个词的重要程度
- 决定应该关注哪些词📖 理论延伸:为什么需要注意力机制?
在Transformer出现之前,处理文本的主流方法是RNN(循环神经网络)。RNN有一个重要问题:长距离依赖。
RNN的问题:
句子:"小明喜欢打篮球,他每天都去打球,他的偶像是姚明。"
RNN处理时:
- 看到"小明"时,记在记忆中
- 处理中间很多词后,记忆逐渐淡化
- 看到"他"时,可能已经不记得"小明"了
结果:可能错误地理解"他"指谁注意力的优势:
注意力机制:
- 处理"他"时,可以"回头看"所有词
- 计算每个词与"他"的相关性
- 直接找到最相关的"小明"
结果:准确理解指代关系理论核心:注意力机制打破了顺序的限制,让每个词都能"看到"所有其他词。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
类比:在教室里找老师
场景:你在教室里找老师
过程:
1. 你有目标(找老师)→ Query(查询)
2. 你看每个人的特征(年龄、衣着)→ Key(键)
3. 确定是不是老师 → Value(值)
注意力计算:
- 目标(Query)和特征(Key)匹配
- 匹配度高,就是老师(Value)技术实现:
输入:一个句子的所有词
对每个词:
1. Query(查询):这个词想找什么?
2. Key(键):其他词是什么?
3. Value(值):其他词的内容是什么?
计算:
1. 计算Query和Key的相似度(得分)
2. 把得分转换成概率(注意力权重)
3. 用权重加权Value
4. 得到输出具体例子:
句子:"猫坐在垫子上"
分析"猫"这个词:
- Query:["猫"的特征向量]
- Key:[所有词的特征向量]
- Value:[所有词的内容]
计算注意力:
"猫"和"猫":得分高(自己)
"猫"和"坐":得分高(猫会坐)
"猫"和"垫子":得分中(猫在垫子上)
"猫"和"在":得分低(不太相关)
结果:
"猫"主要关注"坐"和"垫子"
理解到"猫坐在垫子上"问题1:理解长距离依赖
例子:"小明喜欢打篮球,他每天都去打球,他的偶像是姚明。"
理解"他"指的是谁:
- 需要回到句首的"小明"
- 传统方法很难处理这种长距离关系
- 注意力可以直接关注"小明"问题2:理解重要信息
例子:"虽然今天下雨,但我还是要去上班。"
哪个词更重要?
- "虽然":不太重要
- "下雨":重要
- "但":重要(转折)
- "上班":最重要(核心信息)
注意力可以自动识别"上班"最重要问题3:理解歧义
例子:"苹果很好吃。"
"苹果"可能指:
- 水果苹果
- 苹果公司
注意力机制:
- 如果上下文有"水果",理解为水果
- 如果上下文有"手机",理解为公司
- 根据上下文自动选择正确含义句子:"小明喜欢苹果"
注意力权重(分析"喜欢"):
小明:0.4(喜欢主语)
喜欢:0.2(自己)
苹果:0.4(喜欢宾语)
注意力权重(分析"苹果"):
小明:0.3(主语相关)
喜欢:0.2(动词相关)
苹果:0.5(自己)权重说明:
Transformer的特点:
问题:
句子1:"我爱你"
句子2:"你爱我"
相同的字,不同的顺序,不同的意思
如果模型不知道顺序,会把它们当成一样的方法1:绝对位置编码
给每个位置分配一个编号:
位置1的词:加上位置编码[1, 0, 0, ...]
位置2的词:加上位置编码[0, 1, 0, ...]
位置3的词:加上位置编码[0, 0, 1, ...]
句子:"我爱你"
'我' + [1,0,0] → [我是第1个]
'爱' + [0,1,0] → [我是第2个]
'你' + [0,0,1] → [我是第3个]缺点:
方法2:相对位置编码(RoPE)
关注词与词之间的相对关系
"我"在"爱"前面 → 相对位置-1
"爱"在"你"前面 → 相对位置-1
"我"在"你"前面 → 相对位置-2
模型学习相对位置,而不是绝对位置优势:
例子:
句子:"小猫坐在垫子上"
模型处理:
1. "小":知道自己在第1个位置
2. "猫":知道自己在第2个位置,在"小"后面
3. "坐":知道自己在第3个位置,在"猫"后面
4. "在":知道自己在第4个位置,在"坐"后面
5. "垫":知道自己在第5个位置,在"在"后面
6. "子":知道自己在第6个位置,在"垫"后面
7. "上":知道自己在第7个位置,在"子"后面
结果:
模型理解:小猫(主语)坐在(动作)垫子上(地点)没有位置编码会怎样?
模型看到的只是:[小, 猫, 坐, 在, 垫, 子, 上]
可能理解为:
- 猫坐在小垫子上
- 垫子坐在小猫上
- 小猫坐在上垫子
都是错的!为什么Transformer需要位置编码?
核心问题:Transformer的设计让它可以并行处理所有词,但这也带来了一个问题——它不知道词的顺序。
类比理解:
想象你在玩拼图:
- 所有拼图块都摆在你面前
- 你可以同时看所有块(并行处理)
- 但如果你不知道块的顺序,拼不出完整画面
位置编码就像:
- 给每个拼图块标上编号
- 知道块的位置关系
- 能拼出正确的画面技术原理:
原始Transformer论文使用的是正弦位置编码:
- 使用正弦和余弦函数
- 生成位置相关的向量
- 让模型学习位置模式
我们使用的是RoPE(旋转位置编码):
- 通过旋转操作引入位置信息
- 计算更高效
- 效果更好理论核心:位置编码让Transformer在享受并行计算优势的同时,保留了理解词序的能力。
在继续之前,问问自己:
💡 思考题:


输入层
↓
嵌入层(字符→向量)
↓
位置编码(加上位置信息)
↓
Transformer层(4层,重复)
├─ 注意力层(理解词与词关系)
├─ 前馈网络层(处理信息)
└─ 层归一化(稳定训练)
↓
输出层(向量→概率)
↓
预测下一个词
类比:理解一句话需要多步思考
第1层:理解基本关系
- "猫"和"狗"都是动物
- "跑"和"跳"都是动作
第2层:理解复杂关系
- "猫追狗" → 猫是主动的
- "狗被猫追" → 狗是被动的
第3层:理解更抽象的关系
- "猫追狗是因为猫饿了"
- 理解因果关系
第4层:理解深层含义
- "猫追狗,但没追上"
- 理解转折和结果我们的模型有4层:
维度 = 信息容量
类比:描述一个人
1维(太简单):
- 只能说"好人"或"坏人"
- 信息太少
10维(一般):
- 性格、爱好、职业...
- 能描述基本信息
256维(丰富):
- 性格、爱好、职业、经历、价值观...
- 能描述非常丰富的信息我们的配置:
注意力头 = 不同的关注角度
类比:看电影,不同人关注不同东西
头1:关注语法结构
- "猫"是主语
- "跑"是动词
头2:关注语义关系
- "猫"和"跑":猫会跑
- "狗"和"跑":狗也会跑
头3:关注指代关系
- "它"指的是前面的"猫"
头4:关注其他关系
- 时间、地点、原因...我们的配置:
深层网络的问题:
类比:
考试分数:
- 有人考100分
- 有人考0分
- 如果不标准化,很难比较
标准化后:
- 把分数都转换到相似范围
- 便于比较和分析方法:
1. 计算这一层的平均值和标准差
2. 用标准差把数值归一化
3. 加上可学习的偏移和缩放
结果:
- 数值都在合理范围内
- 训练更稳定
- 收敛更快RMSNorm:
我们使用的是简化版的层归一化:
- 只计算均方根(不需要算均值)
- 计算更快
- 效果相当为什么重要?
没有归一化:
- 数值可能爆炸(变得很大)
- 或者消失(变得很小)
- 训练无法进行
有归一化:
- 数值保持稳定
- 训练顺利进行
- 快速达到好的效果学完这一章,你应该能够:
✅ 解释计算机如何处理文本 ✅ 理解注意力机制的作用 ✅ 知道位置编码的必要性
📖 第二章学习总结
核心概念回顾:
关键要点:
✅ 计算机通过词向量理解文本的语义
✅ 注意力机制解决了长距离依赖问题
✅ 位置编码让模型理解词序和距离关系
✅ 多头注意力让模型从不同角度理解文本
✅ 层归一化稳定训练过程
技术细节:
下一步学习:
自我评估:
如果以上问题的答案都是"是",恭喜你!你已经准备好进入下一章了!🎉
下一步:理解训练是如何进行的
✅ 理解训练的基本原理 ✅ 知道损失函数的作用 ✅ 了解梯度下降的方法 ✅ 掌握优化的关键技术
📍 3.1 训练的基本概念(入门)
↓
📍 3.2 损失函数(如何衡量好坏)
↓
📍 3.3 梯度下降(如何改进)
↓
📍 3.4 训练循环(完整流程)
↓
📍 3.5 优化技术(提升效果)前置知识:理解了模型的基本结构
类比:学生做练习
学生学习的循环:
1. 老师给出一道题
2. 学生尝试解答
3. 老师给出正确答案
4. 学生对比自己的答案
5. 找出错误,改正思路
6. 重复这个过程
AI训练的循环:
1. 给模型一个训练样本
2. 模型尝试预测
3. 计算预测与目标的差距
4. 根据差距调整参数
5. 重复这个过程📖 理论延伸:机器学习 vs 传统编程
传统编程:
程序员写规则:
if 用户说"你好":
回答"你好!"
if 用户说"再见":
回答"再见!"
特点:
- 需要手动编写所有规则
- 规则必须明确
- 难以处理复杂情况机器学习:
机器自己学规则:
训练数据:
("你好", "你好!")
("再见", "再见!")
...
模型学习:
- 发现规律
- 自己生成规则
- 处理未见情况
特点:
- 不需要手动写规则
- 可以处理复杂情况
- 数据越多越好理论核心:传统编程是"告诉计算机怎么做",机器学习是"让计算机自己学会怎么做"。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
最终目标:
让模型学会:
- 输入问题 → 输出正确答案
- 输入未见过的问题 → 输出合理的答案训练过程的目标:
让模型的预测越来越接近正确答案
即:损失函数最小化步骤1:准备数据
我们的训练数据:
[
{"prompt": "什么是注意力机制?",
"completion": "注意力让模型关注重点。"},
{"prompt": "如何让模型关注重点?",
"completion": "使用注意力机制。"},
...
]步骤2:构建输入
把训练样本转换成模型能理解的格式:
用户:什么是注意力机制?
助手:注意力让模型关注重点。
↑
从这里开始预测
步骤3:前向传播
1. 输入文本 → 分词 → 数字ID
2. 数字ID → 词向量
3. 词向量 → 模型 → 预测输出
4. 预测输出 → 概率分布步骤4:计算损失
对比预测和正确答案:
预测:[0.1, 0.7, 0.1, 0.1]
正确:[0.0, 1.0, 0.0, 0.0]
损失 = 计算两者的差距步骤5:反向传播
根据损失计算梯度:
- 每个参数应该怎么调整
- 调整方向和大小步骤6:更新参数
用梯度更新参数:
新参数 = 旧参数 - 学习率 × 梯度步骤7:重复
重复步骤3-6,直到:
- 达到最大训练步数
- 或者验证损失不再下降类比:考试得分
学生的考试:
- 回答问题
- 老师批改
- 给出分数
- 分数越低,说明学得越差
模型的训练:
- 预测答案
- 计算损失
- 损失值
- 损失越低,说明学得越好📖 理论延伸:为什么用交叉熵损失?
问题:如何衡量两个概率分布的差异?
直观理解:
假设模型预测:
- 正确答案的概率:0.9
- 错误答案的概率:0.1
另一个模型预测:
- 正确答案的概率:0.6
- 错误答案的概率:0.4
哪个更好?
- 显然第一个更好
- 但需要一个数字来衡量交叉熵的原理:
公式:H(p, q) = -Σ p(x) log(q(x))
p(x):正确答案的概率分布
q(x):模型预测的概率分布
对于第一个模型:
H = -[1 × log(0.9) + 0 × log(0.1)] = 0.105
对于第二个模型:
H = -[1 × log(0.6) + 0 × log(0.4)] = 0.511结论:第一个模型的损失更小,更好为什么用对数?
对数的特性:
1. 把乘法变成加法(方便计算)
2. 对概率(0-1之间)取对数,结果是负数
3. 负号让损失变成正数
4. 概率越高,损失越小(符合直觉)理论核心:交叉熵损失衡量了模型预测分布和真实分布的差异,是训练语言模型的标准损失函数。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
原理:
比较两个概率分布:
1. 模型预测的概率分布
2. 正确答案的概率分布
计算它们的"距离"(差异)
距离越小,说明预测越准确具体例子:
问题:"什么是注意力机制?"
模型预测:
- "注意力让模型关注重点。" 概率 0.9 ✓
- "它是一种神经网络。" 概率 0.1 ✗
正确答案:
- "注意力让模型关注重点。" 概率 1.0
- "它是一种神经网络。" 概率 0.0
计算损失:
损失 = -log(0.9) = 0.105
损失很小,说明学得好!另一个例子:
问题:"什么是注意力机制?"
模型预测:
- "注意力让模型关注重点。" 概率 0.3
- "它是一种神经网络。" 概率 0.7
正确答案:
- "注意力让模型关注重点。" 概率 1.0
- "它是一种神经网络。" 概率 0.0
计算损失:
损失 = -log(0.3) = 1.204
损失很大,说明学得差!我们的训练过程:
Step 0: loss = 11.38
→ 完全不懂,瞎猜
Step 10: loss = 5.67
→ 开始理解一些基本模式
Step 20: loss = 3.57
→ 理解了不少,但还有错误
Step 40: loss = 1.31
→ 相当不错,大部分能答对
Step 100: loss = 0.39
→ 已经很棒,但开始过拟合
Step 50: loss = 1.00(验证损失最低)
→ 最佳时刻,保存这个模型损失曲线的解读:
训练损失:
↓ ↓ ↓ ↓ ↓ 一直下降(对训练数据越来越熟)
验证损失:
↓ ↓ ↓ ↑ ↑ 先降后升(对新数据先变好再变差)
↑ 这里是最佳时刻类比:下山
你在山上,想下山到山谷:
- 山顶 = 高损失(模型很差)
- 山谷 = 低损失(模型很好)
- 梯度 = 下山的方向
- 学习率 = 每次走多远梯度的含义:
梯度告诉我们:
- 哪个方向能让损失降低
- 应该往哪个方向调整参数
- 调整的幅度是多少📖 理论延伸:梯度的数学含义
数学定义:
梯度是函数变化最快的方向
如果损失函数是 f(x),那么:
梯度 = ∇f(x) = [∂f/∂x₁, ∂f/∂x₂, ...]
每个分量表示:
- 在该方向上的变化率
- 应该往相反方向调整(为了降低损失)直观理解:
想象一个山谷:
/\
/ \
/ \ ← 山顶(高损失)
/ \
/ \ ← 当前位置
/ \
/____________\ ← 山谷(低损失)
梯度指向:从当前位置,最陡峭的上升方向
我们要走:相反方向(下降方向)为什么叫"梯度下降"?
梯度:指向上坡方向
下降:我们要走下坡方向
所以叫"梯度下降":沿着梯度的反方向走理论核心:梯度下降是优化神经网络参数的核心方法,通过沿着损失函数下降的方向调整参数,逐步找到最优解。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
步骤1:计算损失
知道当前位置的损失步骤2:计算梯度
知道下山的方向步骤3:更新参数
往山下走一步
新参数 = 旧参数 - 学习率 × 梯度步骤4:重复
重复1-3,直到到达山谷学习率太大:
问题:可能跳过山谷
例子:
- 山谷在左边
- 一步跨过去,到了右边
- 然后跨回来,到左边
- 反复跳跃,无法到达山谷学习率太小:
问题:下山太慢
例子:
- 每次只走一小步
- 需要很多步才能到达山谷
- 训练时间很长学习率合适:
完美平衡:
- 既不会跳过山谷
- 也不会太慢
- 稳定快速地到达山谷为什么要调整学习率?
类比:学开车
刚开始学:
- 慢慢来,注意细节
- 学习率小一点
熟悉了:
- 可以快一点
- 学习率大一点
快精通了:
- 又要精细调节
- 学习率再小一点Warmup(预热):
训练初期:学习率从0逐渐增加
为什么?
- 模型刚开始很"懵"
- 太大的学习率会"走偏"
- 先慢慢走,熟悉地形后再加速Cosine Annealing(余弦退火):
训练后期:学习率按照余弦曲线降低
为什么?
- 接近最优解,需要精细调节
- 防止在最优解附近震荡
- 稳定地收敛到最优解我们的配置:
最大学习率:0.001
预热步数:20步
最大步数:200步
学习率变化:
0 → 20步:从0增加到0.001
20 → 200步:按照余弦曲线降低到接近0类比:连锁反应
多米诺骨牌:
- 推倒第一个
- 第二个倒下
- 第三个倒下
- ...
- 全部倒下
反向传播:
- 输出层的错误
- 影响隐藏层
- 影响输入层
- 计算所有参数的梯度输入 → 隐藏层1 → 隐藏层2 → 输出计算过程:
1. 输入层接收数据
2. 每一层处理数据
3. 传递到下一层
4. 最终得到输出输出 → 隐藏层2 → 隐藏层1 → 输入计算过程:
1. 计算输出层的误差
2. 误差反向传播到隐藏层
3. 计算每一层的梯度
4. 得到所有参数的梯度前向:从输入到输出
- 数据的正常流动方向
反向:从输出到输入
- 误差的传播方向
- 与前向相反,所以叫反向传播数学原理:
链式法则:
如果 y = f(x) 且 z = g(y)
那么 dz/dx = dz/dy × dy/dx
应用到神经网络:
- 每一层都是一个函数
- 每一层都可以计算导数
- 通过链式法则计算总梯度实际例子:
简单的网络:
输入x → 隐藏层h → 输出y
损失L = (y - target)²
计算梯度:
∂L/∂y = 2(y - target) (输出层)
∂y/∂h = W₂ (隐藏层到输出)
∂h/∂x = W₁ (输入到隐藏层)
总梯度:
∂L/∂W₂ = ∂L/∂y × ∂y/∂W₂
∂L/∂W₁ = ∂L/∂y × ∂y/∂h × ∂h/∂x📖 理论延伸:反向传播的历史和意义
为什么叫"反向传播"?
历史背景:
- 20世纪80年代提出
- 解决了多层神经网络的训练问题
- 是深度学习的基石
核心思想:
- 前向传播:计算每一层的输出
- 反向传播:从后往前计算每一层的梯度
为什么叫"反向"?
- 数据流动方向:前向(输入→输出)
- 梯度计算方向:反向(输出→输入)
- 梯度是反向传播的,所以叫反向传播计算图的理解:
想象一个计算图:
输入x
↓
f₁(x) → a₁
↓
f₂(a₁) → a₂
↓
f₃(a₂) → y
↓
L(y, target)
前向传播:从上到下计算
反向传播:从下到上计算梯度
链式法则的应用:
∂L/∂x = ∂L/∂y × ∂y/∂a₂ × ∂a₂/∂a₁ × ∂a₁/∂x为什么反向传播高效?
问题:计算所有参数的梯度
方法1:数值梯度(不推荐)
- 对每个参数,单独计算梯度
- 复杂度:O(n),n是参数数量
- 非常慢
方法2:反向传播(推荐)
- 一次反向传播,计算所有梯度
- 复杂度:O(1),与参数数量无关
- 非常快
我们的模型有337万参数:
- 数值梯度:需要337万次计算
- 反向传播:只需要1次计算理论核心:反向传播是深度学习训练的核心算法,通过链式法则高效计算所有参数的梯度,使得训练大型神经网络成为可能。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
for step in range(max_steps):
# 1. 获取训练数据
batch = next(data_loader)
# 2. 前向传播
predictions = model(batch)
# 3. 计算损失
loss = compute_loss(predictions, batch.targets)
# 4. 反向传播
loss.backward()
# 5. 更新参数
optimizer.step()
optimizer.zero_grad()
# 6. 定期评估
if step % eval_interval == 0:
val_loss = evaluate(model, val_data)
print(f"Step {step}: train_loss={loss}, val_loss={val_loss}")每一步的详细解释步骤1:获取训练数据
从数据集中取一批数据
我们的数据:
- 6个训练样本
- 每次取1个样本
- 重复使用这些数据步骤2:前向传播
模型处理数据:
1. 分词:文本 → 数字ID
2. 嵌入:ID → 向量
3. Transformer层:向量 → 语义表示
4. 输出层:语义表示 → 概率分布步骤3:计算损失
比较预测和正确答案:
- 预测的概率分布
- 正确答案的概率分布
- 计算交叉熵损失步骤4:反向传播
计算梯度:
- 从损失函数开始
- 反向传播到每一层
- 计算每个参数的梯度步骤5:更新参数
用梯度更新参数:
新参数 = 旧参数 - 学习率 × 梯度
更新所有参数:
- 嵌入层的参数
- Transformer层的参数
- 输出层的参数步骤6:定期评估
在验证集上评估:
- 用验证数据测试模型
- 计算验证损失
- 判断是否需要早停Step 0:
获取数据:"什么是注意力机制?"
前向传播:预测"它是一种神经网络。"
计算损失:loss = 11.38
反向传播:计算梯度
更新参数:调整所有参数
评估:val_loss = 10.23
Step 10:
获取数据:"如何让模型关注重点?"
前向传播:预测"使用注意力。"(接近了)
计算损失:loss = 5.67
反向传播:计算梯度
更新参数:继续调整
评估:val_loss = 6.89
Step 40:
获取数据:"什么是位置编码?"
前向传播:预测"位置编码告诉模型词序。"
计算损失:loss = 1.31
反向传播:计算梯度
更新参数:微调
评估:val_loss = 1.00(最佳!)
Step 50:
评估:val_loss = 1.23(开始变差)
早停触发!
保存Step 40的模型问题:模型学太多会"钻牛角尖"
类比:
考试复习:
- 适度复习:成绩提高
- 过度复习:开始纠结细节,反而变差
AI训练:
- 适度训练:泛化能力好
- 过度训练:过拟合,泛化能力差早停机制的工作原理:
1. 记录最佳验证损失
2. 设置耐心值(patience)
3. 如果连续N次验证损失不改善
4. 停止训练,保存最佳模型我们的配置:
耐心值:10
连续10次验证损失不下降,就停止
实际效果:
Step 40: val_loss = 1.00(最佳)
Step 50: val_loss = 1.23
Step 60: val_loss = 1.45
...
Step 100: val_loss = 1.78(触发早停)问题:小模型容易"死记硬背"
类比:
学习方式:
- 死记硬背:只记住答案,换个问法就不会
- 灵活理解:理解原理,举一反三Dropout的原理:
训练时:
- 随机丢弃一部分神经元(设为0)
- 每次训练丢弃不同的神经元
- 迫使模型学习多条路径
推理时:
- 使用全部神经元
- 相当于多个模型的集成我们的配置:
Dropout比例:0.2
每次训练随机丢弃20%的神经元
效果:
- 减少过拟合
- 提高泛化能力
- 让模型更鲁棒问题:传统注意力计算太慢
优化方法:
传统注意力:
- 一次性计算整个注意力矩阵
- 内存占用大
- 计算慢
Flash Attention:
- 分块计算
- 计算完立即使用
- 不需要存储整个矩阵
效果:
- 速度提升约30%
- 内存占用显著降低
- 为11.5秒训练奠定基础学完这一章,你应该能够:
✅ 理解训练的基本过程 ✅ 知道损失函数的作用 ✅ 了解梯度下降的原理 ✅ 掌握优化的关键技术 ✅ 理解训练如何进行
📖 第三章学习总结
核心概念回顾:
训练流程:
训练循环:
1. 前向传播:计算模型输出
2. 计算损失:评估预测误差
3. 反向传播:计算参数梯度
4. 参数更新:调整模型参数
5. 重复以上步骤直到收敛
优化技术:
- 早停:防止过拟合
- Dropout:提高泛化能力
- 学习率调度:平衡收敛速度和稳定性
- Flash Attention:加速计算关键要点:
✅ 损失函数衡量模型预测的好坏✅ 梯度下降沿着损失下降方向调整参数✅ 反向传播高效计算所有参数的梯度✅ 早停和Dropout防止过拟合✅ 学习率调度平衡训练速度和稳定性
实际训练结果:
下一步学习:
自我评估:
如果以上问题的答案都是"是",恭喜你!你已经掌握了AI训练的核心原理!🎉
下一步:动手训练自己的模型
✅ 准备训练环境 ✅ 准备训练数据 ✅ 执行训练命令 ✅ 验证训练结果
📍 4.1 环境准备(5分钟)
↓
📍 4.2 数据准备(2分钟)
↓
📍 4.3 训练模型(1分钟)
↓
📍 4.4 验证结果(2分钟)前置知识:理解了训练的基本原理
第一步:检查Python版本
python --version要求:
第二步:安装必要的库
pip install torch numpy说明:
torch:深度学习框架numpy:数值计算库验证安装:
python -c "import torch; import numpy; print('安装成功!')"📖 理论到实践:为什么需要这些库?
PyTorch(深度学习框架):
理论联系:
- 第三章讲的前向传播、反向传播
- 第二章讲的Transformer架构
- 这些都需要深度学习框架来实现
PyTorch的作用:
- 自动计算梯度(反向传播)
- 提供神经网络层(Transformer层、嵌入层等)
- GPU加速支持(虽然我们用CPU训练)
- 张量运算(类似NumPy但支持GPU)NumPy(数值计算库):
理论联系:
- 第二章讲的词向量
- 向量之间的计算
- 这些都是数值计算
NumPy的作用:
- 高效的数组运算
- 数学函数(对数、指数等)
- 数据处理和转换理论核心:深度学习框架和数值计算库是实现AI理论的工具,让我们专注于算法设计,而不是底层实现。
🎯 学习检查点:
在继续之前,问问自己:
💡 思考题:
我们的训练数据文件:data/train_simple_6.jsonl
内容示例:
{"prompt": "什么是注意力机制?", "completion": "注意力让模型关注重点。"}
{"prompt": "如何让模型关注重点?", "completion": "使用注意力机制。"}
{"prompt": "为什么需要注意力?", "completion": "为了让模型理解重要信息。"}
{"prompt": "什么是位置编码?", "completion": "位置编码告诉模型词序。"}
{"prompt": "模型怎么知道词的顺序?", "completion": "通过位置编码。"}
{"prompt": "为什么位置编码重要?", "completion": "词序影响句子含义。"}数据特点:原则1:质量优于数量
10个好样本 > 100个差样本
精心设计的数据胜过随意收集原则2:概念覆盖
覆盖核心概念:
- 注意力机制(3个问题)
- 位置编码(3个问题)原则3:问题类型多样化
每种概念3种问题:
1. 定义问题:是什么?
2. 方法问题:怎么做?
3. 原因问题:为什么?原则4:简洁明确
每个答案都是一句话
易于学习,不易出错第一步:训练分词器
python -m src.tokenizer说明:
输出示例:
训练分词器...
词表大小:20000
保存分词器到 checkpoints/tokenizer
完成!第二步:训练模型
python -m src.train说明:
输出示例:
开始训练...
Step 0: train_loss=11.38, val_loss=10.23
Step 10: train_loss=5.67, val_loss=6.89
Step 20: train_loss=3.57, val_loss=4.12
Step 30: train_loss=2.15, val_loss=2.67
Step 40: train_loss=1.31, val_loss=1.00 ✓ 最佳
Step 50: train_loss=0.89, val_loss=1.23触发早停,保存最佳模型(Step 40)
训练完成!实际训练时间:11.44秒
配置文件:config.yaml
model:
n_layer: 4 # 4层Transformer
n_embd: 256 # 256维向量
n_head: 4 # 4个注意力头
dropout: 0.2 # 20% Dropout
training:
max_steps: 200 # 最大200步
lr: 0.001 # 学习率
batch_size: 16 # 批次大小
early_stopping_patience: 10 # 早停耐心值训练时间:
cat checkpoints/train_time.txt输出:
elapsed_seconds=11.44模型大小:
ls -lh checkpoints/model.safetensors输出:
-rw-r--r-- 1 user user 12M checkpoints/model.safetensors说明:
第一步:运行推理
python -m src.infer --prompt "什么是注意力机制?"输出示例:
输入:什么是注意力机制?
输出:注意力让模型关注重点。第二步:测试多个问题
python -m src.infer --prompt "如何让模型关注重点?"
python -m src.infer --prompt "为什么需要注意力?"
python -m src.infer --prompt "什么是位置编码?"预期输出:
输入:如何让模型关注重点?
输出:使用注意力机制。
输入:为什么需要注意力?
输出:为了让模型理解重要信息。
输入:什么是位置编码?
输出:位置编码告诉模型词序。测试逻辑推理:
python -m src.infer --prompt "注意力机制的作用是什么?"预期输出:
输入:注意力机制的作用是什么?
输出:注意力让模型关注重点。说明:
学完这一章,你应该能够:
✅ 准备训练环境 ✅ 准备训练数据 ✅ 执行训练命令 ✅ 验证训练结果 ✅ 测试模型效果
下一步:测试和验证模型
✅ 测试模型的基本功能 ✅ 验证模型的推理能力 ✅ 理解模型的局限性 ✅ 了解优化方向
测试1:什么是注意力机制?
python -m src.infer --prompt "什么是注意力机制?"预期输出:
注意力让模型关注重点。验证:
测试2:如何让模型关注重点?
python -m src.infer --prompt "如何让模型关注重点?"预期输出:
使用注意力机制。验证:
测试3:为什么需要注意力?
python -m src.infer --prompt "为什么需要注意力?"预期输出:
为了让模型理解重要信息。验证:
测试4:什么是位置编码?
python -m src.infer --prompt "什么是位置编码?"预期输出:
位置编码告诉模型词序。验证:
测试5:模型怎么知道词的顺序?
python -m src.infer --prompt "模型怎么知道词的顺序?"预期输出:
通过位置编码。验证:
测试6:为什么位置编码重要?
python -m src.infer --prompt "为什么位置编码重要?"预期输出:
词序影响句子含义。验证:
测试7:注意力机制的作用
python -m src.infer --prompt "注意力机制的作用是什么?"预期输出:
注意力让模型关注重点。验证:
测试8:位置编码的用途
python -m src.infer --prompt "位置编码有什么用?"预期输出:
位置编码告诉模型词序。验证:
测试9:如何使用注意力机制?
python -m src.infer --prompt "如何使用注意力机制?"预期输出:
使用注意力机制。验证:
测试10:解释一下注意力机制和位置编码
python -m src.infer --prompt "解释一下注意力机制和位置编码"预期输出:
注意力让模型关注重点。位置编码告诉模型词序。验证:
特点:
测试:
python -m src.infer --prompt "什么是注意力机制?"结果:
准确率:接近100%特点:
测试1:未学过的概念
python -m src.infer --prompt "什么是BERT?"预期输出:
可能无法回答或回答不准确说明:
测试2:复杂的问题
python -m src.infer --prompt "注意力机制和位置编码有什么区别?"预期输出:
可能无法准确比较两个概念说明:
现象:
原因:
改进方向:
增加数据量
当前:6个样本
目标:60个样本
方法:
- 增加更多概念
- 每个概念更多问题
- 增加问题类型提高数据质量
当前:简单问答
目标:多样化问答
方法:
- 增加长问题
- 增加复杂问题
- 增加多轮对话增加模型大小
当前:337万参数
目标:3370万参数
方法:
- 增加层数(4 → 8)
- 增加嵌入维度(256 → 512)
- 增加注意力头数(4 → 8)增加训练时间
当前:11.5秒
目标:115秒
方法:
- 增加训练步数(200 → 2000)
- 使用更多数据Few-shot学习
给模型一些例子,让它学习:
例子:
Q: 什么是注意力机制?
A: 注意力让模型关注重点。
Q: 什么是位置编码?
A: 位置编码告诉模型词序。
Q: 什么是RMSNorm?
A: (让模型尝试回答)提示工程
优化问题的表述:
坏:"注意力机制"
好:"什么是注意力机制?"
更好的:"请解释一下注意力机制的作用和原理。"学完这一章,你应该能够:
✅ 测试模型的基本功能 ✅ 验证模型的推理能力 ✅ 理解模型的局限性 ✅ 了解优化方向
第一章:AI模型基础
第二章:模型核心组件
第三章:训练过程
第四章:动手训练
第五章:测试验证
训练成果:
学习成果:
推荐学习路径:
第1步:深度学习基础
第2步:Transformer架构
第3步:GPT系列
第4步:训练技术
项目1:扩展数据集
项目2:增大模型
项目3:多轮对话
项目4:特定领域
在线课程:
书籍:
论文:
开源项目:
从零开始到训练完成:
这只是一个开始:
循序渐进:
动手实践:
保持好奇:
社区交流:
发展趋势:
你的机会:
最后:
恭喜你完成了AI入门之旅!
你现在已经:
- 理解了AI的基本原理
- 训练了自己的第一个模型
- 掌握了继续学习的基础
继续探索吧!AI的世界等待你的贡献!祝你学习愉快,AI之旅精彩纷呈!🚀
本文示例的源码:https://github.com/helloworldtang/GPT_teacher-3.37M-cn