【机器学习】(25)—— 反向传播

反向传播:神经网络如何更新权重

文章目录

  • 反向传播:神经网络如何更新权重
    • [1. 和梯度下降的关系](#1. 和梯度下降的关系)
    • [2. 链式法则:为什么能「往回传」](#2. 链式法则:为什么能「往回传」)
    • [3. 微型网络手算](#3. 微型网络手算)
      • [3.1 前向](#3.1 前向)
      • [3.2 前向( y = 0 y=0 y=0)](#3.2 前向( y = 0 y=0 y=0))
      • [3.3 反向](#3.3 反向)
      • [3.4 若 ReLU 关掉了通道](#3.4 若 ReLU 关掉了通道)
    • [4. 一次完整训练迭代](#4. 一次完整训练迭代)
    • [5. 训练时常见的三种故障](#5. 训练时常见的三种故障)
      • [5.1 梯度消失(Vanishing gradients)](#5.1 梯度消失(Vanishing gradients))
      • [5.2 梯度爆炸(Exploding gradients)](#5.2 梯度爆炸(Exploding gradients))
      • [5.3 死 ReLU(Dead ReLU)](#5.3 死 ReLU(Dead ReLU))
    • [6. Dropout:专门给网络用的正则](#6. Dropout:专门给网络用的正则)
    • [7. 动手:NumPy 走通一轮反向](#7. 动手:NumPy 走通一轮反向)
    • [8. 和专栏前文关系](#8. 和专栏前文关系)
    • [9. 能力边界与常见误区](#9. 能力边界与常见误区)
      • [9.1 适用边界](#9.1 适用边界)
      • [9.2 常见误区](#9.2 常见误区)
    • [10. 关键术语速查](#10. 关键术语速查)
    • [11. 延伸阅读](#11. 延伸阅读)
    • [12. 小结](#12. 小结)

摘要 :第 23、24 篇把网络的前向路径搭好了:加权和、激活、得到预测。训练还缺半边------损失怎样告诉每一层的 w , b w,b w,b「往哪改」。反向传播(Backpropagation) 用链式法则,把输出端的误差一层层传回输入端附近的参数,让第 03 篇的梯度下降在多层网络里也能跑。本文讲清前向 / 反向两趟、微型网络手算、梯度消失与死 ReLU 等常见坑,以及 Dropout。适合已理解激活函数的读者。


1. 和梯度下降的关系

第 3 篇的更新公式没有变:

w ← w − η ∂ L ∂ w w \leftarrow w - \eta \frac{\partial L}{\partial w} w←w−η∂w∂L

难的是:网络很深时, ∂ L / ∂ w \partial L/\partial w ∂L/∂w 不再是「一眼能写完」的式子。中间隔着好几层乘加和激活,要对靠输入的那批权重求导,必须把复合函数拆开。

反向传播 干的就是这件事:按计算图从损失往回走,用链式法则乘上每一段的局部导数,高效得到所有参数的梯度。框架(如常见的自动微分库)通常替你算完;专栏仍要搞清它在干什么,否则学习率、激活、层数出问题时会无从下手。

可以把它想成工厂质检:前向是成品装配,反向是根据不合格报告逐站追查该拧哪颗螺丝。螺丝很多时,不能每颗都从头拆整机------沿装配顺序的逆序传误差,才是可扩展的做法。

方向 产出
前向 输入 → 输出 预测 y ′ y' y′、损失 L L L
反向 损失 → 各层参数 ∂ L / ∂ w \partial L/\partial w ∂L/∂w、 ∂ L / ∂ b \partial L/\partial b ∂L/∂b
更新 --- 用学习率 η \eta η 改参数

2. 链式法则:为什么能「往回传」

设一条极简路径:

z = w x , a = ReLU ⁡ ( z ) , y ′ = v a , L = 1 2 ( y ′ − y ) 2 z = w x,\quad a = \operatorname{ReLU}(z),\quad y' = v a,\quad L = \tfrac{1}{2}(y'-y)^2 z=wx,a=ReLU(z),y′=va,L=21(y′−y)2

要求 ∂ L / ∂ w \partial L/\partial w ∂L/∂w。链式法则:

∂ L ∂ w = ∂ L ∂ y ′ ⋅ ∂ y ′ ∂ a ⋅ ∂ a ∂ z ⋅ ∂ z ∂ w \frac{\partial L}{\partial w} = \frac{\partial L}{\partial y'} \cdot \frac{\partial y'}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w} ∂w∂L=∂y′∂L⋅∂a∂y′⋅∂z∂a⋅∂w∂z

每一段只依赖局部运算:

局部导数 含义
∂ L / ∂ y ′ = y ′ − y \partial L/\partial y' = y'-y ∂L/∂y′=y′−y 预测偏高还是偏低
∂ y ′ / ∂ a = v \partial y'/\partial a = v ∂y′/∂a=v 输出层权重
∂ a / ∂ z \partial a/\partial z ∂a/∂z ReLU: z > 0 z>0 z>0 为 1,否则 0
∂ z / ∂ w = x \partial z/\partial w = x ∂z/∂w=x 该权重对应的输入

反向传播按层复用中间结果,避免对每个权重从头展开整棵式子------层数一多,这种复用才关键。

数值上不必自己推到纸面极限:把「局部导数连乘」记熟,再对照框架里某层 grad 是否接近 0 或异常大,就能把第 5 节的三类故障对上号。


3. 微型网络手算

沿用汽车风格的小数:输入 x = 2.0 x=2.0 x=2.0(可理解为已缩放的重量),标签 y = 1.0 y=1.0 y=1.0(示意)。

隐藏一个神经元 + ReLU,再接到输出:

参数 初值
w w w(输入→隐藏) 0.5 0.5 0.5
b b b 0.0 0.0 0.0
v v v(隐藏→输出) 1.0 1.0 1.0
c c c(输出偏置) 0.0 0.0 0.0

3.1 前向

z = 0.5 × 2.0 + 0 = 1.0 a = ReLU ⁡ ( 1.0 ) = 1.0 y ′ = 1.0 × 1.0 + 0 = 1.0 L = 1 2 ( 1.0 − 1.0 ) 2 = 0 \begin{aligned} z &= 0.5\times 2.0 + 0 = 1.0 \\ a &= \operatorname{ReLU}(1.0) = 1.0 \\ y' &= 1.0\times 1.0 + 0 = 1.0 \\ L &= \tfrac{1}{2}(1.0-1.0)^2 = 0 \end{aligned} zay′L=0.5×2.0+0=1.0=ReLU(1.0)=1.0=1.0×1.0+0=1.0=21(1.0−1.0)2=0

这次碰巧预测对了,梯度全 0,参数不动。把标签改成 y = 0 y=0 y=0,再走一遍。

3.2 前向( y = 0 y=0 y=0)

y ′ y' y′ 仍是 1.0 1.0 1.0, L = 1 2 ( 1 − 0 ) 2 = 0.5 L=\tfrac{1}{2}(1-0)^2=0.5 L=21(1−0)2=0.5。

3.3 反向

∂ L ∂ y ′ = 1.0 ∂ L ∂ v = ∂ L ∂ y ′ ⋅ a = 1.0 ∂ L ∂ a = ∂ L ∂ y ′ ⋅ v = 1.0 ∂ L ∂ z = ∂ L ∂ a ⋅ 1 z \> 0 = 1.0 ∂ L ∂ w = ∂ L ∂ z ⋅ x = 2.0 ∂ L ∂ b = ∂ L ∂ z = 1.0 \begin{aligned} \frac{\partial L}{\partial y'} &= 1.0 \\ \frac{\partial L}{\partial v} &= \frac{\partial L}{\partial y'}\cdot a = 1.0 \\ \frac{\partial L}{\partial a} &= \frac{\partial L}{\partial y'}\cdot v = 1.0 \\ \frac{\partial L}{\partial z} &= \frac{\partial L}{\partial a}\cdot 1_{z\>0} = 1.0 \\ \frac{\partial L}{\partial w} &= \frac{\partial L}{\partial z}\cdot x = 2.0 \\ \frac{\partial L}{\partial b} &= \frac{\partial L}{\partial z} = 1.0 \end{aligned} ∂y′∂L∂v∂L∂a∂L∂z∂L∂w∂L∂b∂L=1.0=∂y′∂L⋅a=1.0=∂y′∂L⋅v=1.0=∂a∂L⋅1z\>0=1.0=∂z∂L⋅x=2.0=∂z∂L=1.0

取 η = 0.1 \eta=0.1 η=0.1:

v ← 1.0 − 0.1 × 1.0 = 0.9 w ← 0.5 − 0.1 × 2.0 = 0.3 b ← 0.0 − 0.1 × 1.0 = − 0.1 \begin{aligned} v &\leftarrow 1.0 - 0.1\times 1.0 = 0.9 \\ w &\leftarrow 0.5 - 0.1\times 2.0 = 0.3 \\ b &\leftarrow 0.0 - 0.1\times 1.0 = -0.1 \end{aligned} vwb←1.0−0.1×1.0=0.9←0.5−0.1×2.0=0.3←0.0−0.1×1.0=−0.1

下一轮前向, y ′ y' y′ 会变小,朝 y = 0 y=0 y=0 靠近。多层网络只是把「 ∂ L / ∂ a \partial L/\partial a ∂L/∂a」继续拆到更前面的层,算法结构相同。

3.4 若 ReLU 关掉了通道

假设某次前向算出 z = − 0.3 z=-0.3 z=−0.3,则 a = 0 a=0 a=0,且 ∂ a / ∂ z = 0 \partial a/\partial z=0 ∂a/∂z=0,于是 ∂ L / ∂ w = 0 \partial L/\partial w=0 ∂L/∂w=0、 ∂ L / ∂ b = 0 \partial L/\partial b=0 ∂L/∂b=0。这一步里,输入侧权重收不到误差信号------这就是死 ReLU 的雏形。输出侧的 v v v 仍可能有梯度(若后面还有通路),但该隐藏单元本身暂时「听不见」损失在喊什么。

这也解释了为何初始化与学习率不能乱拧:一步把大量单元打进负区,等于空手练其中一半网络。


4. 一次完整训练迭代

text 复制代码
取一个 batch
  → 前向得到 y' 与 L
  → 反向得到各层梯度
  → w,b 按学习率更新
  → 重复;用验证集做早停(第 21 篇)

损失仍可选 MSE(回归)或 Log Loss(分类,第 07 篇)。反向传播不绑定某一种损失,它只负责「在给定 L L L 时求梯度」。

批量训练时,先对 batch 内样本的梯度取平均(或求和再按约定缩放),再更新一次参数------与第 03、04 篇的 batch 思想一致。网络更深时,同一 η \eta η 可能显得过大,需要重新在验证集上搜。


5. 训练时常见的三种故障

5.1 梯度消失(Vanishing gradients)

靠近输入的层,梯度是很多「小于 1 的因子」连乘,可能变得极小,那些层几乎不更新。深层网络 + Sigmoid/tanh 饱和时更明显。第 24 篇推荐隐藏层用 ReLU,正是为了减轻这个问题。

5.2 梯度爆炸(Exploding gradients)

权重很大时,连乘结果过大,参数一步跳飞,损失尖峰(第 21 篇曲线)。可降低学习率;实践中也常用梯度裁剪、更好的初始化,以及后续会接触的归一化手段。

5.3 死 ReLU(Dead ReLU)

某单元长期 z < 0 z<0 z<0,输出恒为 0,反向时 ∂ a / ∂ z = 0 \partial a/\partial z=0 ∂a/∂z=0,梯度过不去,它可能一直醒不过来。学习率过大、初始化不当会加重。可减小 η \eta η,或改用 Leaky ReLU 等变体。

排查时可看:有多少比例的隐藏激活长期为 0?若接近「半边网络熄火」,先降学习率,再考虑换激活或检查输入是否未标准化(第 14 篇)------量纲奇怪时, z z z 更容易大面积掉进负区。


6. Dropout:专门给网络用的正则

第 07、21 篇讲过 L2。神经网络里还有常用的 Dropout:训练时按概率随机把一些神经元的激活置零,相当于每步都在训练一个略有缺失的子网络,减轻共适应、抑制过拟合。

丢弃率 含义
0 0 0 不用 Dropout
接近 1 1 1 几乎全丢,学不动
中间值(如 0.2 0.2 0.2~ 0.5 0.5 0.5) 常见试验区间,当超参用验证集选

推理时一般关闭 Dropout,并用合适的缩放保证输出期望一致(框架会处理)。Dropout 与 L2、早停可以一起用,但仍解决不了数据泄漏与划分错误(第 19 篇)。

直觉上,Dropout 强迫网络不能把宝押在某几个神经元上;这对参数很多的全连接层尤其有用。宽度很小的玩具网络上,Dropout 收益有限,甚至干扰拟合------仍以验证集为准。


7. 动手:NumPy 走通一轮反向

python 复制代码
import numpy as np

# 单样本:x=重量示意, y=目标
x, y = 2.0, 0.0
w, b, v, c = 0.5, 0.0, 1.0, 0.0
eta = 0.1

# 前向
z = w * x + b
a = max(z, 0.0)          # ReLU
y_pred = v * a + c
L = 0.5 * (y_pred - y) ** 2
print("forward:", dict(z=z, a=a, y_pred=y_pred, L=L))

# 反向
dL_dy = y_pred - y
dL_dv = dL_dy * a
dL_dc = dL_dy
dL_da = dL_dy * v
dL_dz = dL_da * (1.0 if z > 0 else 0.0)
dL_dw = dL_dz * x
dL_db = dL_dz
print("grads:", dict(dw=dL_dw, db=dL_db, dv=dL_dv, dc=dL_dc))

# 更新
w -= eta * dL_dw
b -= eta * dL_db
v -= eta * dL_dv
c -= eta * dL_dc
print("updated:", dict(w=w, b=b, v=v, c=c))

# 再前向看损失是否下降
z2 = w * x + b
a2 = max(z2, 0.0)
y2 = v * a2 + c
L2 = 0.5 * (y2 - y) ** 2
print("loss after one step:", L, "->", L2)

预期:一步之后 L L L 下降, y ′ y' y′ 向 0 0 0 靠近。真实项目用框架的 loss.backward() 即可,但亲手乘一遍链式法则,遇到「某层不学」时更好定位是消失、爆炸还是死 ReLU。

若把上面脚本放进循环跑几十步,并打印每步 L L L,就能看到与第 03 篇类似的下降曲线;加上验证集后,也能复现第 18、21 篇「训练还在降、验证已抬头」的分叉------那时该早停或加 Dropout,而不是继续猛降学习率到学不动为止。


8. 和专栏前文关系

篇章 在反向传播里的位置
第 3 篇 梯度下降更新公式
第 7 篇 分类用 Log Loss; + + + L2
第 23~24 篇 前向结构与激活,决定局部导数长什么样
第 18~21 篇 验证曲线、早停、复杂度,训练外环不变

自动微分让你很少手写 ∂ L / ∂ w \partial L/\partial w ∂L/∂w,但学习率、深度、激活、Dropout 仍要人来定。反向传播把「能训多层」变成日常,并不取消第 22 篇的检查清单。

汽车例子里:若用浅层网络预测 MPG 或是否高效,训练循环与逻辑回归相同------只是梯度来自更长的计算链。验证损失抬头时,优先查过拟合与学习率,而不是怀疑「反向传播公式写错了」(在框架里那极少是根因)。


9. 能力边界与常见误区

9.1 适用边界

  • 本篇建立直觉与手算;卷积、注意力等结构的反向由框架完成,道理仍是链式法则。
  • Batch Norm、进阶初始化等可缓解爆炸 / 消失,后续实践篇再展开。
  • 小表格数据上,浅层网络 + 强基线往往够用,不必一上来很深。

9.2 常见误区

误区 正解
反向传播是另一种优化算法 它是算梯度的方法;优化仍是 GD / Adam 等
有框架就不用懂反向 不懂则难排查消失、死 ReLU、lr 过大
层越深一定越好训 更深更易消失 / 过拟合
Dropout 推理时也开着 训练开、推理关(按框架默认)
损失不降只怪反向传错了 先查数据、学习率、激活与标签
一次手算就会训生产模型 手算建立直觉;规模化靠框架与验证集

把反向传播学到手的标志,不是能默写长公式,而是能解释:这一步梯度从哪来、为何某层可能收不到、学习率该往大还是往小拧。


10. 关键术语速查

术语 含义
反向传播 用链式法则从损失回传各参数梯度
链式法则 复合函数求导:局部导数连乘
梯度消失 / 爆炸 靠前层梯度过小 / 过大
死 ReLU 单元卡在负区,梯度长期为 0
Dropout 训练时随机丢弃激活以正则化
自动微分 框架按计算图自动求梯度

11. 延伸阅读

资源 适合看什么
专栏第 03 篇 梯度下降四步循环
专栏第 24 篇 ReLU 与梯度消失直觉
专栏第 21 篇 训练曲线与早停
NumPy 手写微型反向时的数组运算

12. 小结

反向传播让多层网络也能做梯度下降:前向算损失,反向用链式法则得到 ∂ L / ∂ w \partial L/\partial w ∂L/∂w,再按学习率更新。手算微型例子是为了看清 ReLU 的局部导数如何切断或放行梯度;训练时还要提防消失、爆炸与死 ReLU,并用 Dropout、L2、早停控制过拟合。

text 复制代码
前向:x → ... → y' → L
反向:L → ... → ∂L/∂w
更新:w ← w − η ∂L/∂w

下一篇做神经网络单元的练习向收束:用浅层网络去拟合非线性分隔,并把学习率、网络宽度、激活函数放在一起对照着调。

系列导航


如果本篇对你有帮助,欢迎点赞、收藏、关注博主,机器学习专栏持续更新中,下次更新不迷路。

相关推荐
Python私教1 小时前
Godot第一个项目怎么创建?三种渲染器到底怎么选
人工智能
染指11101 小时前
64.高级RAG-摄取管道
人工智能·llama_index·llamaindex·摄取管道
再渊1 小时前
基因归因到底怎么计算的?
python·深度学习·机器学习
中微极客1 小时前
神经形态计算:从忆阻器到SNN训练工程实践
人工智能·mvc
Python私教1 小时前
Godot怎么下载和安装?零基础完成第一次启动
人工智能·游戏·godot
Bony-1 小时前
AI产品经理需掌握的通用能力
人工智能·产品经理
树谷-胡老师1 小时前
MaxENT生态位模型的物种适生区预测(全球尺度+中国尺度+省级尺度+市县尺度+保护区尺度)超详细教程!
人工智能
SEO_juper1 小时前
2026_GEO_AI搜索技术实战_CSDN
人工智能·chrome·目标检测·seo·geo·谷歌优化
暴躁的大熊1 小时前
机器学习中的知识图谱:概念、核心技术与应用场景
人工智能·机器学习·知识图谱
Pokerhead1 小时前
如何评价 DeepSeek-V4 的价格?
人工智能·大模型·ai编程·deepseek