01 / 从输入到参数更新
模型学习,就是反复更新参数
用线性回归举例:ŷ = wx + b。数据 x、y 已给定,模型要学习的是参数 w、b。通常不直接给模型正确参数,而是让它根据预测误差逐步调整。
02 / 回归:预测值偏离目标多少?
均方误差:逐个平方,再取平均
先看一个样本:真实值 y=3,预测值 ŷ=1。误差是 1−3=−2,平方误差是 (−2)²=4。平方让正负误差都产生非负损失,也让较大的误差受到更大的惩罚。
对于 n 个样本、每个样本一个输出,均方误差(MSE)定义为:
这里没有额外的 1/2 系数,因此后面的梯度会出现系数 2。不同教材可能采用不同系数,推导时要与损失定义保持一致。
实验 A:逐个样本算损失
三组数据满足 y=2x+1。拖动参数,观察误差怎样变化。
| x | 真实 y | 预测 wx+b | 误差 | 误差² |
|---|
试着把 w 调到 2、b 调到 1。再保持 b=1,只改变 w,观察误差是否会随 x 改变。
03 / 分类:给正确答案多少概率?
交叉熵:惩罚低估正确答案的概率
二分类中,标签 y 是 0 或 1;模型输出 p,表示“标签为 1”的预测概率。例如 y=1 时,预测 p=0.9 比 p=0.1 更合理。
ln 是自然对数。先把这条规则理解为:模型给真实类别的概率越小,损失越大;自信地答错,会受到很大的惩罚。两个公式分支分别对应真实类别 1 与 0。
实验 B:改变预测概率
多分类时呢?实际代码为什么常使用 logits?
多分类、单个正确类别时,交叉熵也是 −ln(正确类别的预测概率)。例如猫、狗、鸟的概率为 [0.1,0.7,0.2],真实类别是狗,则损失为 −ln(0.7)≈0.3567。
逻辑回归通过 sigmoid 把原始分数转为二分类概率;多分类常使用 softmax。训练库常提供直接接收原始分数 logits 的损失函数,以改善数值稳定性。此处用概率讲解含义,具体 API 在 PyTorch 部分再学习。
04 / 损失对参数的变化率
梯度告诉你局部该往哪个方向改
先只看参数 w。若导数为正,局部增大 w 会增大损失,所以应减小 w;若导数为负,则应增大 w。多个参数的偏导数组成梯度。
η(eta)是学习率,控制每次移动多远。梯度只描述局部变化,学习率过大时,一次更新可能跨过低损失区域,甚至导致发散。
用一个样本手算
已知 x=2,y=5,w=1,b=0:
- 预测:
ŷ=1×2+0=2。 - 误差:
e=2−5=−3;损失:L=e²=9。 - 梯度:
∂L/∂w=2ex=−12,∂L/∂b=2e=−6。
实验 C:同一个梯度,不同学习率
多个样本的线性回归梯度
损失是样本平方误差的平均,因此梯度也是各个样本梯度的平均:
对一个输出、二维数组 X:(n,F)、W:(F,1)、y:(n,1),代码为:
error = X @ W + b - y # (n, 1)
grad_W = 2 / len(X) * X.T @ error # (F, 1)
grad_b = 2 * error.mean(axis=0) # (1,)预测和标签的形状必须一致,避免第一节提到的意外广播。
05 / 用哪些样本决定这次更新?
全批量、随机梯度与小批量
对完整训练集平均求梯度,叫全批量梯度下降;每次随机选一个样本更新,叫随机梯度下降(SGD);每次使用一小组样本,叫小批量梯度下降。实际使用中,人们也常把小批量方式统称为 SGD。
| 方法 | 这里的批次大小 | 每次更新的数据 |
|---|---|---|
| 全批量 | 6 | 全部 6 个样本 |
| 小批量 | 2 | 2 个样本的平均梯度 |
| 随机梯度 | 1 | 1 个样本的梯度 |
实验 D:看这一批数据怎样推动模型
六个样本大致满足 y=2x+1,并带有固定的小扰动。每个 epoch 使用固定种子的随机打乱顺序;重新开始会重置参数和样本顺序。
改变批次大小会重新开始;改变学习率影响接下来的更新,点击“重新开始”可从同一起点比较。
模型直线与目标数据
完整六个样本上的 MSE
06 / 让优化更容易进行
特征缩放与参数初始化
为什么单位会影响训练?
同一个长度可以用米或毫米表示,数值相差 1000 倍。预测含义不必改变,但损失对参数的变化速度会改变,原来的学习率可能不再合适。
在线性回归的平方损失中,w 方向的二阶导数包含 x²。输入数值放大 1000 倍,这个方向的曲率会放大 100 万倍,使优化更容易出现不稳定或不同参数方向进展不均衡。
一种常见处理是标准化:x标准化=(x−均值)/标准差。均值与标准差在训练数据上计算;常数特征需要单独处理,避免除以零。标准化通常能改善优化,但不保证任意学习率都稳定。
为什么神经网络通常用随机初始化?
线性回归可以从 w=0、b=0 开始。但如果同一隐藏层的多个神经元拥有完全相同的输入权重、偏置和对称的连接,它们会得到相同的输出与更新,难以学出不同特征。
下方只有一个隐藏神经元,用固定参数方便手算,不用于说明多神经元的随机初始化效果。
07 / 沿计算关系往回求导
反向传播:一条链,四个参数
考虑一个隐藏神经元和一个线性输出的小网络。输入 x=2,目标 y=1;初始参数为 w₁=0.5、b₁=0、w₂=1、b₂=0。
tanh 把输入平滑映射到 −1 与 1 之间;本例只需要知道它的导数是 1−tanh(z₁)²=1−h²。
实验 E:逐步展开计算图
每步使用同一组初始参数,显示值四舍五入,实际计算保留完整精度。
08 / 给推导找一个独立检查方法
用数值差分验证梯度
把某个参数 θ 增大一点、减小一点,分别重新计算损失,估计导数:
每次只改变一个参数,其他参数保持不变。手推梯度与数值估计相近,会给推导多一项证据。ε 太大近似不准,太小又容易受浮点误差影响。
同一小网络:解析梯度 vs 数值梯度
| 参数 | 解析梯度 | 数值梯度 | 绝对差 |
|---|
解析梯度来自链式法则;数值梯度通过扰动参数、重新运行前向计算得到。
配套 NumPy 代码
下载第二节练习代码。包含 MSE、BCE、手写反向传播、数值梯度检查,以及三种批次大小的线性回归训练。在终端进入项目根目录后运行:
uv run python lessons/lesson-02-practice.py运行后输出梯度对比,并在代码文件旁的 lesson-02-output 目录导出训练记录 CSV。本页提供训练曲线,配套代码只依赖 NumPy。
本节练习
- 手算 x=2、y=5、w=1、b=0 时的损失和两个梯度,验证 η=0.1 的更新结果。
- 解释 y=0 时,为什么 p=0.99 会产生很大的交叉熵。
- 用 batch size=1、2、6 训练相同的 epoch 数,观察完整数据上的损失。
- 遮住答案,沿计算图推导 w₁、b₁、w₂、b₂ 的梯度。
- 修改配套小网络的参数或样本,用数值差分检查梯度公式。
09 / 完成标准