广哥在硅谷 · 用思考抵达清晰,用行动靠近自由
CS231n · 深度学习经典讲义

反向传播详解
从计算图直觉到向量化梯度

Backpropagation: From Circuits Intuition to Vectorized Gradients
CS231n · Stanford 中文精校版 9 章 · 约 25 分钟阅读
📋 内容摘要

本文是 Stanford CS231n 课程关于反向传播的核心讲义。它不是教你用框架去自动求导,而是带你建立一种"实数电路的反向流动"的工程直觉。读完这篇,你会知道:为什么加法门是"梯度分发器"、最大门是"梯度路由器"、乘法门是"梯度交换器";为什么矩阵梯度只看维度就能推出来;为什么数据预处理会影响学习率。这种直觉,是你设计、调试和发明新神经网络结构的内功。

章节目录
  1. 引言:为什么要理解反向传播
    Introduction · Motivation
  2. 简单表达式与梯度的解释
    Simple expressions, interpreting the gradient
  3. 复合表达式:链式法则与反向传播
    Compound expressions, chain rule
  4. 反向传播的直觉:每个门都是局部的
    Intuitive understanding
  5. 模块化:Sigmoid 示例
    Modularity: Sigmoid example
  6. 实战:分阶段反向传播
    Backprop in practice: Staged computation
  7. 反向流动中的模式
    Patterns in backward flow
  8. 向量化运算的梯度
    Gradients for vectorized operations
  9. 总结:从直觉到工程
    Summary
CHAPTER 01 · INTRODUCTION

引言:为什么要理解反向传播

Motivation & Problem Statement
📌 本节核心要点

动机

本节的目标是建立对反向传播直觉——它本质上是通过链式法则递归计算梯度的方法。理解它的过程与微妙之处,对你有效地设计、开发和调试神经网络是至关重要的。

问题陈述

给定一个函数 $f(x)$,其中 $x$ 是输入向量。我们关心的是:在某个点 $x$ 处计算 $f$ 的梯度,也就是 $\nabla f(x)$。

为什么这事关重大

在神经网络的场景里,$f$ 是损失函数 $L$,输入 $x$ 包括训练数据和神经网络的权重。比如,$f$ 可以是 SVM 损失,输入是训练样本 $(x_i, y_i)$ 和参数 $(W, b)$。训练数据通常是给定且固定的,权重才是我们能调整的变量。所以虽然我们可以用反向传播算输入的梯度,但实际中我们主要算的是参数的梯度,用来做参数更新。

Backpropagation Chain Rule Gradient Loss Function

每个学神经网络的人,最终都要面对一个问题:这个庞大的、由成百上千万参数构成的模型,到底是怎么"学"起来的?

答案是反向传播——一种通过链式法则递归地计算梯度的方法。它是神经网络训练的核心引擎,是所有深度学习框架(PyTorch、TensorFlow、JAX)底层都在做的事情。

但本文不是教你怎么调框架的 API,而是要带你建立一种更深的认知:反向传播是一种实数电路中的反向流动。这种视角不仅会让你"理解"反向传播,更会让你在未来设计新结构、调试梯度异常、定位训练问题时,直接"看到"梯度在网络里的流动方式

即使你已经能熟练用链式法则手推梯度,也建议你至少读一遍这篇文章。因为它呈现的视角——把反向传播看作实数电路里的反向流动——是一种很少有人系统讨论的角度,能在整个学习过程中持续给你启发。

广哥在硅谷◆ ◆ ◆
CHAPTER 02 · FOUNDATION

简单表达式与梯度的解释

Simple expressions and interpretation of the gradient
📌 本节核心要点

我们先从最简单的两数运算(乘法、加法、最大值)开始,建立符号与约定。关键是要理解:导数告诉你的,是"整个表达式对该变量值的敏感程度"。这个直觉会贯穿后面所有的推导。

Partial Derivative Multiplication Max Gate

我们从最简单的入手——两个数相乘 $f(x,y) = xy$。求偏导数是基础微积分:

$$f(x,y) = xy \quad\Rightarrow\quad \frac{\partial f}{\partial x} = y,\quad \frac{\partial f}{\partial y} = x$$

怎么解释它?记住,导数告诉你的是:函数在某个点附近、对该变量的变化率。形式化地写出来就是:

$$\frac{df(x)}{dx} = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}$$

这里有个小细节:左边的"除号"和右边的除号不是一回事。左边其实是一个算子——$\frac{d}{dx}$ 作用在函数 $f$ 上,返回一个新的函数(导函数)。一个好的理解方式是:当 $h$ 很小时,函数被一条直线很好地近似,而导数就是这条直线的斜率。

换句话说,每个变量的导数告诉你"整个表达式对它的值有多敏感"

举个例子:如果 $x = 4$、$y = -3$,那么 $f(x,y) = -12$,且 $\partial f / \partial x = -3$。这告诉我们:如果把 $x$ 增加一个极小的量,整个表达式会减少(因为符号是负的),减少的量是这个增量的 3 倍。这可以从一个变形看出:$f(x+h) = f(x) + h \cdot \frac{df(x)}{dx}$。同理,$\partial f / \partial y = 4$,意味着把 $y$ 增加一点 $h$,输出会增加 $4h$。

每个变量的导数,告诉你的是整个表达式对它的值有多敏感。

— THE CORE INTUITION OF GRADIENTS

所谓"梯度"$\nabla f$,就是所有偏导数构成的向量。所以对乘法函数我们有:

$$\nabla f = \left[\frac{\partial f}{\partial x},\, \frac{\partial f}{\partial y}\right] = [y, x]$$

虽然技术上"梯度"是一个向量,但为了行文方便,我们经常会说"$x$ 上的梯度",其实指的是"$f$ 对 $x$ 的偏导数"。

加法和最大值的导数也很简单:

$$f(x,y) = x + y \quad\Rightarrow\quad \frac{\partial f}{\partial x} = 1,\quad \frac{\partial f}{\partial y} = 1$$

无论 $x, y$ 的值是多少,加法对两个输入的偏导数都是 1。这很合理:增加 $x$ 或 $y$ 都会等量地增加 $f$,而且这个增加率与 $x, y$ 的具体取值无关(这一点和乘法相反)。

$$f(x,y) = \max(x,y) \quad\Rightarrow\quad \frac{\partial f}{\partial x} = \mathbb{1}(x \geq y),\quad \frac{\partial f}{\partial y} = \mathbb{1}(y \geq x)$$

也就是说,最大值函数的"次梯度"(subgradient)是:在较大的那个输入上是 1,另一个输入上是 0

直觉上想:如果输入是 $x = 4, y = 2$,那么最大值是 4,函数对 $y$ 的值不敏感——把 $y$ 加上一个很小的 $h$,函数还是输出 4,所以梯度是 0:没有效果。当然,如果你把 $y$ 改大一点(比如加上大于 2),那 $f$ 的值会变化,但导数只能告诉你输入有微小变化时的影响,对大变化的影响它什么也说明不了。这就是定义里那个 $\lim_{h \to 0}$ 的含义。

广哥在硅谷◆ ◆ ◆
CHAPTER 03 · CHAIN RULE

复合表达式:链式法则与反向传播

Compound expressions with chain rule
📌 本节核心要点

面对由多个函数复合的表达式,我们不直接求整体导数,而是拆成多个简单步骤,分别求局部梯度,然后通过乘法把它们链接起来——这就是链式法则。这是反向传播的雏形。

Chain Rule Forward Pass Backward Pass

现在考虑更复杂的表达式,比如 $f(x, y, z) = (x + y) z$。这个表达式直接求导也不难,但我们要用一种不一样的方法——这种方法会帮你理解反向传播背后的直觉。

这个表达式可以拆成两步:

$$q = x + y, \quad f = qz$$

这两步我们都会算了。$f$ 是 $q$ 和 $z$ 的乘积,所以 $\partial f / \partial q = z$,$\partial f / \partial z = q$。$q$ 是 $x$ 和 $y$ 的和,所以 $\partial q / \partial x = 1$,$\partial q / \partial y = 1$。

但我们其实不关心中间变量 $q$ 的梯度——$\partial f / \partial q$ 这个值本身没用。我们最终想要的,是 $f$ 对它输入 $x, y, z$ 的梯度。

链式法则告诉我们:把这些梯度表达式正确地"链"起来的方式是乘法。比如:

$$\frac{\partial f}{\partial x} = \frac{\partial f}{\partial q} \cdot \frac{\partial q}{\partial x}$$

在实践中,这就是把两个存放梯度的数字相乘。我们用代码看一个例子:

PYTHON
# 设定输入
x = -2; y = 5; z = -4

# 前向传播(forward pass)
q = x + y       # q = 3
f = q * z       # f = -12

# 反向传播(backward pass),逆序执行:
# 先经过 f = q * z
dfdz = q        # df/dz = q,所以 z 上的梯度是 3
dfdq = z        # df/dq = z,所以 q 上的梯度是 -4
dqdx = 1.0
dqdy = 1.0

# 然后经过 q = x + y
dfdx = dfdq * dqdx   # 这里的乘法就是链式法则!
dfdy = dfdq * dqdy

我们最终得到的是 [dfdx, dfdy, dfdz],它们告诉我们:变量 $x, y, z$ 对 $f$ 的敏感程度。这就是反向传播最简单的例子。

后面我们会用更简洁的记号:省略 df 前缀,直接写 dq 而不是 dfdq,并且始终默认梯度是相对于最终输出而言

📊 计算图可视化

整个计算可以用电路图很直观地展示出来。前向传播从输入沿着边一路计算到输出(绿色数字),反向传播从末端开始,递归地应用链式法则,把梯度(红色数字)一路传回输入。梯度可以被想象成在电路里"反向流动"

x -2 -4 y 5 -4 z -4 3 + 3 -4 × -12 1 f
绿色为前向传播的值,橙色为反向传播的梯度。
梯度从输出端反向流回到每一个输入。
广哥在硅谷◆ ◆ ◆
CHAPTER 04 · INTUITION

反向传播的直觉:每个门都是局部的

Intuitive understanding of backpropagation
📌 本节核心要点

反向传播之所以漂亮,是因为它是一个纯粹局部的过程。每个"门"在接收输入后,立刻能算两件事:输出值输出对输入的局部梯度。当反向传播来临时,它只需要把"从上游传下来的梯度"乘以"自己的局部梯度",再传给下游。门完全不需要知道自己嵌入在多大、多复杂的网络里。

Local Process Gate Local Gradient

注意一件事:反向传播是一个完全局部(local)的过程。电路图里的每个门,在拿到输入的那一刻,可以立刻独立完成两件事:

1. 计算它的输出值;
2. 计算输出相对于输入的局部梯度。

注意,门完全不需要知道自己嵌入在多大的电路里就能做这两件事。然而,前向传播一旦结束,在反向传播过程中,这个门最终会"得知"自己的输出对整个电路最终输出的梯度。链式法则说,门应该把这个梯度乘以它正常计算的每一个对输入的局部梯度,再传下去。

我们用前面的例子来培养直觉。加法门接收了输入 $[-2, 5]$,计算出输出 $3$。因为是加法运算,它对两个输入的局部梯度都是 $+1$。电路其余部分计算出了最终值 $-12$。

反向传播开始后,加法门(作为乘法门的输入)"得知"它的输出梯度是 $-4$。

如果我们把电路拟人化,想象它"希望输出一个更高的值",那么我们可以把电路理解为:它"希望"加法门的输出更低(因为符号是负的),并且"用力"4。为了继续递归并链接梯度,加法门拿着这个 $-4$,乘以它对每个输入的局部梯度(都是 1),得到 $x$ 和 $y$ 上的梯度都是 $1 \times -4 = -4$。

注意这正好达到了预期效果:如果 $x, y$ 响应它们的负梯度而减小,加法门的输出就会减小,进而让乘法门的输出增大

反向传播,可以理解为电路里各个门之间通过梯度信号互相沟通:
它们各自表达"希望自己的输出变大还是变小,以及力度多大",
从而让整个电路的最终输出更高。

— THE BEAUTIFUL LOCALITY OF BACKPROP
广哥在硅谷◆ ◆ ◆
CHAPTER 05 · MODULARITY

模块化:Sigmoid 示例

Modularity: Sigmoid example
📌 本节核心要点

"门"是任意可微分函数。我们可以把多个门合并为一个,也可以把一个函数拆成多个门。合并的好处是:有些复杂表达式(比如 Sigmoid)的导数在合并后会简化成异常优雅的形式,计算更快、数值更稳。这就是模块化的力量。

Sigmoid Activation Function Modularity

前面引入的几个门(加、乘、最大)其实是相当任意的选择。任何可微分函数都可以充当一个门。我们可以把多个门组合成一个,也可以把一个函数拆解成多个门,只要方便。

看一个例子:

$$f(w, x) = \frac{1}{1 + e^{-(w_0 x_0 + w_1 x_1 + w_2)}}$$

后面课程会讲到,这个表达式描述了一个使用 Sigmoid 激活函数的二维神经元(输入 $x$,权重 $w$)。但现在我们就把它当作一个简单的"从输入 $w, x$ 映射到一个数"的函数。

它由多个门组成。除了之前的加、乘、最大门,这里还多了四个:

$$f(x) = \frac{1}{x} \;\Rightarrow\; \frac{df}{dx} = -\frac{1}{x^2}$$ $$f_c(x) = c + x \;\Rightarrow\; \frac{df}{dx} = 1$$ $$f(x) = e^x \;\Rightarrow\; \frac{df}{dx} = e^x$$ $$f_a(x) = ax \;\Rightarrow\; \frac{df}{dx} = a$$

其中 $f_c$ 和 $f_a$ 分别表示"将输入加上常数 $c$"和"将输入乘以常数 $a$"。它们技术上是加法和乘法的特例,这里把它们当成一元门引入,因为我们不需要对常数 $c, a$ 求梯度

整个电路展开来是 8 个门,从输入端依次:乘法($w_0 x_0$)、乘法($w_1 x_1$)、加法、加法(加上 $w_2$)、乘以 $-1$、$e^x$、加 1、取倒数。

这是一长串函数依次应用,作用在 $w, x$ 的点积结果上。我们把这一连串运算实现的函数叫做 Sigmoid 函数 $\sigma(x)$。它的导数推导(稍微有点技巧,需要在分子里加 1 减 1)化简后会变得异常简洁

$$\sigma(x) = \frac{1}{1 + e^{-x}}$$ $$\frac{d\sigma(x)}{dx} = \frac{e^{-x}}{(1 + e^{-x})^2} = \left(\frac{1 + e^{-x} - 1}{1 + e^{-x}}\right)\left(\frac{1}{1 + e^{-x}}\right) = (1 - \sigma(x)) \cdot \sigma(x)$$

这是一个惊人的简化。比如 Sigmoid 收到输入 $1.0$、计算出输出 $0.73$,那么它的局部梯度就直接是 $(1 - 0.73) \cdot 0.73 \approx 0.2$——和电路图里一步步算出来的结果一样,但这里用一个简单、高效的表达式就完成了(而且数值上更稳定)。

所以在实际应用中,把这些运算打包成一个门非常有用。我们看看这个神经元的反向传播代码:

PYTHON
w = [2, -3, -3]    # 假设的随机权重
x = [-1, -2]        # 输入数据

# 前向传播
dot = w[0]*x[0] + w[1]*x[1] + w[2]
f = 1.0 / (1 + math.exp(-dot))   # sigmoid 函数

# 反向传播(通过整个神经元)
ddot = (1 - f) * f          # 用 sigmoid 的简化公式直接算
dx = [w[0] * ddot, w[1] * ddot]      # 传到 x
dw = [x[0] * ddot, x[1] * ddot, 1.0 * ddot]  # 传到 w

# 完成!我们得到了所有输入的梯度
🔧 实现技巧 · 分阶段反向传播

如代码所示,实践中一个非常有用的习惯是:把前向传播拆分成容易反向传播的多个阶段。比如这里我们创建了一个中间变量 dot 来保存 $w$ 和 $x$ 的点积。反向传播时我们再依次倒着计算对应的梯度变量(如 ddot,以及最终的 dwdx)。

这一节的重点是:反向传播的细节如何执行,以及我们把前向函数的哪些部分看作"门",是一种便利性选择关键是要清楚哪些部分有简单的局部梯度,这样它们可以以最少的代码与精力链接在一起。

广哥在硅谷◆ ◆ ◆
CHAPTER 06 · PRACTICE

实战:分阶段反向传播

Backprop in practice: Staged computation
📌 本节核心要点

面对一个更复杂的、嵌套的函数,不要试图直接对原函数求导——那样会得到极其冗长、易错的表达式。正确做法是把前向传播拆分为多个中间变量,然后逐个反向传播。两个关键细节:缓存前向值分叉处梯度要累加(用 += 而不是 =)。

Staged Computation Cache Forward Values Gradients Add at Forks

我们用另一个例子来看这一点。假设有这样一个函数:

$$f(x, y) = \frac{x + \sigma(y)}{\sigma(x) + (x + y)^2}$$

说实话,这个函数完全没用,也看不出谁会想算它的梯度——它纯粹是反向传播实战的一个好例子。要强调的是:如果你直接对 $x$ 或 $y$ 求导,会得到一个极其庞大、复杂的表达式。但好消息是——我们根本不需要写出梯度的显式公式。我们只要会计算它就行了。

下面是这种表达式的前向传播写法:

PYTHON · 前向传播
x = 3       # 示例值
y = -4

# 前向传播
sigy = 1.0 / (1 + math.exp(-y))  # 分子里的 sigmoid  (1)
num = x + sigy                       # 分子                (2)
sigx = 1.0 / (1 + math.exp(-x))  # 分母里的 sigmoid  (3)
xpy = x + y                          #                    (4)
xpysqr = xpy**2                       #                    (5)
den = sigx + xpysqr                  # 分母                (6)
invden = 1.0 / den                   #                    (7)
f = num * invden                     # 完成!              (8)

呼,前向传播算完了。注意我们结构化了代码,让中间变量都很简单——每个都是我们已经知道局部梯度的小表达式。所以反向传播就很容易:我们倒着走,对每一个变量(sigy, num, sigx, xpy, xpysqr, den, invden)都会有一个 d 开头的对应变量,保存最终输出对它的梯度。每一步都涉及"计算局部梯度 + 与上游梯度相乘"。我们用注释标注每行对应前向传播的哪一步:

PYTHON · 反向传播
# backprop f = num * invden
dnum = invden                                        #(8)
dinvden = num                                        #(8)

# backprop invden = 1.0 / den
dden = (-1.0 / (den**2)) * dinvden            #(7)

# backprop den = sigx + xpysqr
dsigx = (1) * dden                                #(6)
dxpysqr = (1) * dden                              #(6)

# backprop xpysqr = xpy**2
dxpy = (2 * xpy) * dxpysqr                        #(5)

# backprop xpy = x + y
dx = (1) * dxpy                                   #(4)
dy = (1) * dxpy                                   #(4)

# backprop sigx = 1.0 / (1 + math.exp(-x))
dx += ((1 - sigx) * sigx) * dsigx  # 注意 += !见下方说明  (3)

# backprop num = x + sigy
dx += (1) * dnum                                  #(2)
dsigy = (1) * dnum                                #(2)

# backprop sigy = 1.0 / (1 + math.exp(-y))
dy += ((1 - sigy) * sigy) * dsigy                 #(1)
# 完成!
💾 实践要点一 · 缓存前向变量

计算反向传播时,你会大量用到前向传播中算出的中间变量。所以实践中要把代码结构化好,让这些变量在反向传播时可用。如果实在不行,也可以重新计算它们(虽然有点浪费)。

➕ 实践要点二 · 分叉处梯度要累加

前向表达式里 $x, y$ 出现了多次(比如 $x$ 既出现在分子 num,又出现在 sigx、又出现在 xpy),所以反向传播时必须用 += 而不是 =,来累加梯度,否则就会被覆盖。这遵循了多变量链式法则:如果一个变量在电路里分叉到不同部分,反向流回它的梯度需要相加

广哥在硅谷◆ ◆ ◆
CHAPTER 07 · PATTERNS

反向流动中的模式

Patterns in backward flow
📌 本节核心要点

神经网络里最常用的三个门——加、乘、最大——在反向传播时各自呈现出非常直观的"性格":

理解这些模式,你才能"看见"梯度在网络里的流动方式。

Add Gate Max Gate Multiply Gate Data Preprocessing

有意思的是,反向流动的梯度在许多场景下都有非常直观的解释。神经网络中最常用的三个门——加、乘、最大——在反向传播时各有非常简单的"行为模式"。

加法门是梯度的分发器
最大门是梯度的路由器
乘法门是梯度的交换器

— THE THREE PATTERNS OF BACKWARD FLOW

加法门会把"对它输出的梯度"原样分发给所有输入,无论它们在前向传播时的值是多少。这是因为加法的局部梯度都是 $+1.0$,所以输入梯度等于输出梯度乘以 1,保持不变。在前面的示例电路里,加法门把 $2.00$ 的梯度原封不动地分给了它的两个输入。

最大门会路由梯度。与加法门把梯度发给所有输入不同,最大门只把梯度(原样地)发给其中一个输入——那个在前向传播时值最大的输入。这是因为最大门的局部梯度对于最大值那个输入是 $1.0$,对其他输入是 $0$。在示例电路里,最大门把梯度 $2.00$ 路由给了 $z$(因为 $z$ 比 $w$ 大),而 $w$ 上的梯度仍然是零。

乘法门稍微难理解一点。它的局部梯度是输入值的"互换",再与上游梯度相乘。在示例里,$x$ 上的梯度是 $-8.00$,等于 $-4.00 \times 2.00$。

⚠ 非直觉的结果及其后果

注意:如果乘法门的一个输入非常小,另一个非常大,乘法门会做一件略反直觉的事——它会给小输入分配相对巨大的梯度,给大输入分配微小的梯度

在线性分类器中,权重和输入做点积(也就是乘法),这意味着:数据的尺度会影响权重梯度的大小。举个例子,如果你把所有输入数据都乘以 1000(预处理时不小心做了这件事),那么权重上的梯度就会大 1000 倍——你必须把学习率相应降低 1000 倍才能补偿。这就是为什么预处理至关重要,且有时影响微妙。理解梯度如何流动,能帮你 debug 这些隐蔽的问题。

广哥在硅谷◆ ◆ ◆
CHAPTER 08 · VECTORIZED

向量化运算的梯度

Gradients for vectorized operations
📌 本节核心要点

前面讲的都是标量的运算,但所有概念都能直接推广到矩阵和向量。最 tricky 的运算是矩阵-矩阵乘法。这里有一个工程上极其有用的技巧——维度分析:你不需要死记 dW、dX 的公式,根据矩阵形状反推就行了。

Matrix Multiplication Dimension Analysis Transpose

之前讨论的都是单变量,但所有概念都可以直接推广到矩阵和向量运算。不过这里要多花点心思去关注维度转置

矩阵-矩阵乘法的梯度可能是最 tricky 的一个运算(它涵盖了所有矩阵-向量、向量-向量乘法的情况):

PYTHON · 矩阵乘法的梯度
# 前向传播
W = np.random.randn(5, 10)
X = np.random.randn(10, 3)
D = W.dot(X)

# 假设上游传过来的梯度是 dD
dD = np.random.randn(*D.shape)   # 和 D 形状相同
dW = dD.dot(X.T)   # .T 是矩阵的转置
dX = W.T.dot(dD)
🧠 工程技巧 · 用维度分析

不需要记住 dW 和 dX 的公式——根据维度可以重新推导出来!

比如我们知道:权重的梯度 dW 必须和 W 的形状一样,而它必须涉及到 X 和 dD 的某种矩阵乘法(就像标量情形那样)。只有一种排列方式能让维度对得上。

举例:X 的形状是 $[10 \times 3]$,dD 是 $[5 \times 3]$。如果我们想要 dW(形状必须是 $[5 \times 10]$),那么唯一的可能就是 dD.dot(X.T)——dD 是 $[5 \times 3]$,X.T 是 $[3 \times 10]$,乘出来正好是 $[5 \times 10]$。

📝 学习建议 · 从小例子推导

如果你一开始觉得向量化推导很难,建议先写出一个最小的、显式的向量化例子,在纸上推导梯度,然后把这种模式泛化到高效的向量化形式

Erik Learned-Miller 也写过一篇更长的关于矩阵/向量求导的笔记,需要时可以参考。

广哥在硅谷◆ ◆ ◆
CHAPTER 09 · SUMMARY

总结:从直觉到工程

Summary & Looking Forward
📌 本节核心要点

让我们快速回顾这一篇的核心收获。

第一,我们建立了对梯度含义的直觉:它告诉我们电路对每个输入的敏感程度。我们看到了它如何在电路中反向流动,如何"告诉"电路的不同部分:你应该增大还是减小,用多大的力,才能让最终输出更高。

第二,我们讨论了分阶段计算对实际反向传播的重要性。你应该总是把函数拆成你能轻易推导出局部梯度的模块,然后用链式法则把它们串起来。

关键一点:你几乎永远不会想把整个梯度表达式写在纸上然后符号微分。因为你根本不需要一个显式的梯度数学公式。所以——分解你的表达式为多个阶段,每个阶段能独立求导(这些阶段会是矩阵-向量乘法、最大值运算、求和运算等等),然后一步步地对每个变量反向传播。

反向传播不是"算"出来的,
"流"出来的。
把网络看成电路,把梯度看成信号——这就是你的内功心法。

— TAKEAWAY

下一节我们会开始定义神经网络,而反向传播会让我们高效地计算损失函数对参数的梯度。换句话说,我们已经准备好训练神经网络了——这门课中最概念性、最难的部分已经过去了!之后讲卷积网络,就只是一小步距离了。