神经网络看起来可能只是一串矩阵运算,但每一步都会改变数值的含义。沿着一个小型网络从输入追踪到输出,就能看清整个过程:矩阵形状决定哪些映射可以连接,偏置会平移这些映射,秩限制独立方向,而激活函数会改变组合所能表达的内容。
学完后,你将能够逐步追踪每个形状,手算或用 NumPy 计算一个两层网络,并说明偏置、秩和激活分别会在何处影响结果。
本课综合了三个此前学过的工具:不显式求逆来解线性系统 、用核与像描述丢失和可达的方向 ,以及用偏置平移仿射映射 。《Mathematics for Machine Learning 》第 2 章提供了这次综合所需的线性代数基础。下面的网络、数字、代码、图示和练习均为原创内容。
逐层追踪两个仿射层的维度
这里的“两层网络”指两个可学习的仿射映射,中间夹着一个隐藏层激活函数。我们将输出保留为两个分数,不再应用概率转换或类别判定。设输入为列向量 x ∈ R 2 x\in\mathbb{R}^2 x ∈ R 2 。每个仿射映射都由矩阵和偏置向量组合而成:
两层网络及其形状
z = W 1 x + b 1 , W 1 ∈ R 2 × 2 , b 1 ∈ R 2 , z ∈ R 2 , h = σ ( z ) , h ∈ R 2 , y = W 2 h + b 2 , W 2 ∈ R 2 × 2 , b 2 ∈ R 2 , y ∈ R 2 . \begin{aligned}
z &= W_1x+b_1, & W_1&\in\mathbb{R}^{2\times 2}, & b_1&\in\mathbb{R}^2, & z&\in\mathbb{R}^2,\\
h &= \sigma(z), & h&\in\mathbb{R}^2,\\
y &= W_2h+b_2, & W_2&\in\mathbb{R}^{2\times 2}, & b_2&\in\mathbb{R}^2, & y&\in\mathbb{R}^2.
\end{aligned} z h y = W 1 x + b 1 , = σ ( z ) , = W 2 h + b 2 , W 1 h W 2 ∈ R 2 × 2 , ∈ R 2 , ∈ R 2 × 2 , b 1 b 2 ∈ R 2 , ∈ R 2 , z y ∈ R 2 , ∈ R 2 . 隐藏向量 z z z 是第一个仿射映射的激活前结果。函数 σ \sigma σ 作用于它的每个坐标;在本例中,σ \sigma σ 是 ReLU,即 σ ( t ) = max ( 0 , t ) \sigma(t)=\max(0,t) σ ( t ) = max ( 0 , t ) 。激活函数保持形状不变,因此 h h h 仍是一个有两个坐标的向量,可以传给第二个矩阵。
相邻映射之间的共享维度必须匹配:W 1 W_1 W 1 有两列,对应两个输入特征;它有两行,对应两个隐藏层输出。接着 W 2 W_2 W 2 接收这两个隐藏值,并返回两个输出分数。偏置 b 1 b_1 b 1 分别加到每个隐藏坐标上,b 2 b_2 b 2 则分别加到每个输出上。维度不兼容的矩阵无法执行所述映射;这与 NumPy 矩阵乘积所做的形状检查相同。
追踪一个双输入、双隐藏单元的网络 移动任一输入坐标,或切换隐藏层规则。初始状态为 x = (1, 1) 且使用 ReLU;下方所有数值都在 JavaScript 运行前渲染。 输入 · 2 个特征 仿射映射 · 2 个隐藏值 隐藏层激活 仿射映射 · 2 个分数 输出 · 2 个分数 z = W₁x + b₁
h = σ(z)
y = W₂h + b₂
更改输入和隐藏层规则 使用方向键或滑块更改每个输入,范围为 −2 到 2,步长为 0.25。
输入 x₁ 1.00 输入 x₂ 1.00
隐藏层规则 ReLU 恒等映射(无激活)
激活前 z (-0.50 , 0.50 )
隐藏层输出 h (0.00 , 0.50 )
分数 y (1.50 , -0.50 )
激活的隐藏单元 1 / 2
局部雅可比矩阵的秩 1 某个激活前值恰好为零,此处 ReLU 有折点。该点的雅可比矩阵未定义;查看任一相邻区域即可了解其局部秩。
初始输入为 1、1;隐藏层输出为 0、0.5;分数为 1.5、−0.5。
图示中的初始值使用以下固定且由人工选定的参数:
W 1 = [ 1 − 1 1 1 ] , b 1 = [ − 0.5 − 1.5 ] , W 2 = [ 1 2 − 1 1 ] , b 2 = [ 0.5 − 1 ] 。 W_1=\begin{bmatrix}1&-1\\1&1\end{bmatrix},\quad
b_1=\begin{bmatrix}-0.5\\-1.5\end{bmatrix},\quad
W_2=\begin{bmatrix}1&2\\-1&1\end{bmatrix},\quad
b_2=\begin{bmatrix}0.5\\-1\end{bmatrix}。 W 1 = [ 1 1 − 1 1 ] , b 1 = [ − 0.5 − 1.5 ] , W 2 = [ 1 − 1 2 1 ] , b 2 = [ 0.5 − 1 ] 。
这个例子足够小,可以逐项追踪。所选数值旨在展示 ReLU 如何关闭一个隐藏单元;它们不是训练得到的参数,也不代表典型模型。
计算一次预测,保留每个中间结果
取 x = ( 1 , 1 ) T x=(1,1)^\mathsf{T} x = ( 1 , 1 ) T 。第一个矩阵用不同方式组合两个输入坐标,再加上偏置,平移每个结果:
包含 ReLU 隐藏步骤的前向传播
z = W 1 x + b 1 = [ 1 − 1 1 1 ] [ 1 1 ] + [ − 0.5 − 1.5 ] = [ 0 2 ] + [ − 0.5 − 1.5 ] = [ − 0.5 0.5 ] , h = ReLU ( z ) = [ max ( 0 , − 0.5 ) max ( 0 , 0.5 ) ] = [ 0 0.5 ] , y = W 2 h + b 2 = [ 1 2 − 1 1 ] [ 0 0.5 ] + [ 0.5 − 1 ] = [ 1 0.5 ] + [ 0.5 − 1 ] = [ 1.5 − 0.5 ] 。 \begin{aligned}
z &= W_1x+b_1
= \begin{bmatrix}1&-1\\1&1\end{bmatrix}
\begin{bmatrix}1\\1\end{bmatrix}
+\begin{bmatrix}-0.5\\-1.5\end{bmatrix}
= \begin{bmatrix}0\\2\end{bmatrix}
+\begin{bmatrix}-0.5\\-1.5\end{bmatrix}
= \begin{bmatrix}-0.5\\0.5\end{bmatrix},\\[4pt]
h &= \operatorname{ReLU}(z)
= \begin{bmatrix}\max(0,-0.5)\\\max(0,0.5)\end{bmatrix}
= \begin{bmatrix}0\\0.5\end{bmatrix},\\[4pt]
y &= W_2h+b_2
= \begin{bmatrix}1&2\\-1&1\end{bmatrix}
\begin{bmatrix}0\\0.5\end{bmatrix}
+\begin{bmatrix}0.5\\-1\end{bmatrix}
= \begin{bmatrix}1\\0.5\end{bmatrix}
+\begin{bmatrix}0.5\\-1\end{bmatrix}
= \begin{bmatrix}1.5\\-0.5\end{bmatrix}。
\end{aligned} z h y = W 1 x + b 1 = [ 1 1 − 1 1 ] [ 1 1 ] + [ − 0.5 − 1.5 ] = [ 0 2 ] + [ − 0.5 − 1.5 ] = [ − 0.5 0.5 ] , = ReLU ( z ) = [ max ( 0 , − 0.5 ) max ( 0 , 0.5 ) ] = [ 0 0.5 ] , = W 2 h + b 2 = [ 1 − 1 2 1 ] [ 0 0.5 ] + [ 0.5 − 1 ] = [ 1 0.5 ] + [ 0.5 − 1 ] = [ 1.5 − 0.5 ] 。 每一步的形状依次为 ( 2 × 2 ) ( 2 , ) + ( 2 , ) = ( 2 , ) (2\times2)(2,)+(2,)=(2,) ( 2 × 2 ) ( 2 , ) + ( 2 , ) = ( 2 , ) ,然后激活函数保持形状 ( 2 , ) (2,) ( 2 , ) ,接着是 ( 2 × 2 ) ( 2 , ) + ( 2 , ) = ( 2 , ) (2\times2)(2,)+(2,)=(2,) ( 2 × 2 ) ( 2 , ) + ( 2 , ) = ( 2 , ) 。得到的 y y y 是两个分数。还需要单独的输出规则,才能将它们转换为标签或概率分布。
NumPy 的 @ 运算符执行矩阵乘法。下面的 + b 运算使用 NumPy 的逐元素广播,将长度为二的偏置加到长度为二的结果上。这段小程序会打印实际的中间向量:
import numpy as np
W1 = np.array([[ 1.0 , - 1.0 ], [ 1.0 , 1.0 ]]) # (2, 2)
b1 = np.array([ - 0.5 , - 1.5 ]) # (2,)
W2 = np.array([[ 1.0 , 2.0 ], [ - 1.0 , 1.0 ]]) # (2, 2)
b2 = np.array([ 0.5 , - 1.0 ]) # (2,)
x = np.array([ 1.0 , 1.0 ]) # (2,)
z = W1 @ x + b1 # (2,) = (2, 2) @ (2,) + (2,)
h = np.maximum(z, 0.0 ) # (2,), elementwise ReLU
y = W2 @ h + b2 # (2,) = (2, 2) @ (2,) + (2,)
print ( 'z:' , z) # [-0.5 0.5]
print ( 'h:' , h) # [0. 0.5]
print ( 'y:' , y) # [ 1.5 -0.5]
相同的宽度逻辑也适用于一批样本。如果将 B B B 个样本按行存储,数组形状为 ( B , 2 ) (B,2) ( B , 2 ) ;右乘 W 1 T W_1^\mathsf{T} W 1 T 后得到形状为 ( B , 2 ) (B,2) ( B , 2 ) 的隐藏值,再右乘 W 2 T W_2^\mathsf{T} W 2 T 得到形状为 ( B , 2 ) (B,2) ( B , 2 ) 的分数。PyTorch 的 Linear 层采用这种按行排列的约定:其权重形状为 ( out features , in features ) (\text{out features},\text{in features}) ( out features , in features ) ,并执行 y = x A T + b y=xA^\mathsf{T}+b y = x A T + b 。因此,Linear(2, 2) 保存一个形状为 ( 2 , 2 ) (2,2) ( 2 , 2 ) 的权重和一个长度为二的偏置。PyTorch 的 ReLU 逐元素应用并保持输入形状,与上面的步骤一致(Linear 文档 、ReLU 文档 、NumPy matmul 文档 )。
没有激活函数时,两层仍可合并为一个仿射映射
仿射层中的偏置起平移作用。如果隐藏层步骤是恒等映射,可以通过代入将两层合成为:
y = W 2 ( W 1 x + b 1 ) + b 2 = ( W 2 W 1 ) x + ( W 2 b 1 + b 2 ) 。 y=W_2(W_1x+b_1)+b_2
=(W_2W_1)x+(W_2b_1+b_2)。 y = W 2 ( W 1 x + b 1 ) + b 2 = ( W 2 W 1 ) x + ( W 2 b 1 + b 2 ) 。
因此,堆叠更多没有非线性激活的仿射映射,并不能把整体输入输出规则变成非线性规则;矩阵会相乘并合并为一个矩阵,偏置也会合并为一个偏移量。使用本例所选数值,W 2 W 1 = [ 3 1 0 2 ] W_2W_1=\begin{bmatrix}3&1\\0&2\end{bmatrix} W 2 W 1 = [ 3 0 1 2 ] ,且 W 2 b 1 + b 2 = ( − 3 , − 2 ) T W_2b_1+b_2=(-3,-2)^\mathsf{T} W 2 b 1 + b 2 = ( − 3 , − 2 ) T 。因此,采用恒等映射时,( 1 , 1 ) T (1,1)^\mathsf{T} ( 1 , 1 ) T 会映射到 ( 1 , 0 ) T (1,0)^\mathsf{T} ( 1 , 0 ) T 。
矩阵的秩 表示其独立输出方向的数量。在这个恒等映射示例中,W 1 W_1 W 1 和 W 2 W_2 W 2 的秩都是二,它们的乘积秩也为二。如果网络的隐藏层宽度为 r r r ,仿射组合的线性部分的秩不可能大于 r r r ,因为它只通过 r r r 个坐标进行分解。如果任一矩阵的秩更低,组合后的秩还可能更低。这些都是上界:窄层可能形成瓶颈,但仅凭宽度无法保证具体的秩。
ReLU 使映射成为分段仿射函数
当隐藏单元的激活前值为负数时,ReLU 会将其变为零。在所有激活前值符号保持不变的任一区域内,激活单元的集合也固定不变。令 D D D 为对角矩阵,其中每个激活的 ReLU 单元对应一个 1 1 1 ,每个未激活单元对应一个 0 0 0 。在该区域内,两层网络的局部线性部分为
J = W 2 D W 1 。 J=W_2DW_1。 J = W 2 D W 1 。
对于上面的输入,z = ( − 0.5 , 0.5 ) T z=(-0.5,0.5)^\mathsf{T} z = ( − 0.5 , 0.5 ) T ,所以 D = [ 0 0 0 1 ] D=\begin{bmatrix}0&0\\0&1\end{bmatrix} D = [ 0 0 0 1 ] 。于是
J = [ 1 2 − 1 1 ] [ 0 0 0 1 ] [ 1 − 1 1 1 ] = [ 2 2 1 1 ] , rank ( J ) = 1 。 J=
\begin{bmatrix}1&2\\-1&1\end{bmatrix}
\begin{bmatrix}0&0\\0&1\end{bmatrix}
\begin{bmatrix}1&-1\\1&1\end{bmatrix}
=\begin{bmatrix}2&2\\1&1\end{bmatrix},
\qquad \operatorname{rank}(J)=1。 J = [ 1 − 1 2 1 ] [ 0 0 0 1 ] [ 1 1 − 1 1 ] = [ 2 1 2 1 ] , rank ( J ) = 1 。
在该输入附近,只要第一个隐藏单元仍未激活,两个输出分数都会随相同的输入组合 x 1 + x 2 x_1+x_2 x 1 + x 2 改变;差异方向 ( 1 , − 1 ) (1,-1) ( 1 , − 1 ) 不会产生影响。矩阵 J J J 描述的是该激活区域内的局部变化,而不是整个网络共用的一个全局矩阵。在 ReLU 的边界上,如果激活前值等于零,函数会出现折点,因此没有任何一个相邻区域的雅可比矩阵能够描述边界两侧。
隐藏层宽度和权重也会限制网络可以表达的内容。在这个特定示例中,两条激活前值为零的直线将输入平面划分为若干区域,每个区域具有不同的激活单元模式;每个区域都有一条仿射规则,跨越一条直线时,这条规则可能改变。更一般地说,加入非线性激活函数可以使非线性函数成为可能,但并不意味着权重的任意取值都能表达复杂函数。隐藏单元可能对关注的输入始终不激活,矩阵也可能压缩方向。矩阵形状、秩、偏置偏移量和激活模式共同决定网络的行为。
这就是为什么仅看输出值只能提供有限的调试信息。追踪形状可以发现不兼容的连接;比较 z z z 和 h h h 可以看到哪些特征被门控;检查层的秩或局部雅可比矩阵,可以识别丢失的方向。如果单独的拟合步骤要求你求解 A x ≈ b Ax\approx b A x ≈ b ,第 025 课 解释了数值求解器为何可以避免构造 A − 1 A^{-1} A − 1 的风险。网络的前向传播本身会使用矩阵乘积,不需要对学得的权重求逆。
看清这些映射和方向后,接下来要问的是向量有多大。第 039 课介绍范数 ,用于衡量向量大小、比较嵌入尺度并描述参数惩罚。
检查理解情况
Question 1
对于本课中的网络,请列出 x、W₁、b₁、z、h、W₂、b₂ 和 y 的形状。为什么 W₂ 可以接收 h?
Show the step-by-step solution x x x 的形状为 ( 2 , ) (2,) ( 2 , ) ,W 1 W_1 W 1 为 ( 2 , 2 ) (2,2) ( 2 , 2 ) ,b 1 b_1 b 1 为 ( 2 , ) (2,) ( 2 , ) ,而 z z z 和 h h h 都是 ( 2 , ) (2,) ( 2 , ) 。第二个矩阵 W 2 W_2 W 2 为 ( 2 , 2 ) (2,2) ( 2 , 2 ) ,其偏置 b 2 b_2 b 2 的形状为 ( 2 , ) (2,) ( 2 , ) ,输出 y y y 的形状为 ( 2 , ) (2,) ( 2 , ) 。W 2 W_2 W 2 的内维度为二,与 h h h 的两个分量匹配;因此该矩阵可将隐藏向量映射为两个输出分数。
Question 2
当 x = (1, 1)ᵀ 时,使用本课的矩阵和 ReLU 计算 z、h 和 y。请展示偏置与激活步骤。
Show the step-by-step solution 首先 W 1 x = ( 0 , 2 ) T W_1x=(0,2)^\mathsf{T} W 1 x = ( 0 , 2 ) T ,加上 b 1 = ( − 0.5 , − 1.5 ) T b_1=(-0.5,-1.5)^\mathsf{T} b 1 = ( − 0.5 , − 1.5 ) T 后得到 z = ( − 0.5 , 0.5 ) T z=(-0.5,0.5)^\mathsf{T} z = ( − 0.5 , 0.5 ) T 。逐坐标应用 ReLU,得到 h = ( 0 , 0.5 ) T h=(0,0.5)^\mathsf{T} h = ( 0 , 0.5 ) T 。接着 W 2 h = ( 1 , 0.5 ) T W_2h=(1,0.5)^\mathsf{T} W 2 h = ( 1 , 0.5 ) T ;再加上 b 2 = ( 0.5 , − 1 ) T b_2=(0.5,-1)^\mathsf{T} b 2 = ( 0.5 , − 1 ) T ,得到 y = ( 1.5 , − 0.5 ) T y=(1.5,-0.5)^\mathsf{T} y = ( 1.5 , − 0.5 ) T 。
Question 3
为什么移除隐藏层激活函数后仍然是一个仿射映射?请计算本例中合并后的矩阵和偏置。
Show the step-by-step solution 将第一个仿射规则代入第二个:W 2 ( W 1 x + b 1 ) + b 2 = ( W 2 W 1 ) x + ( W 2 b 1 + b 2 ) W_2(W_1x+b_1)+b_2=(W_2W_1)x+(W_2b_1+b_2) W 2 ( W 1 x + b 1 ) + b 2 = ( W 2 W 1 ) x + ( W 2 b 1 + b 2 ) 。这里矩阵乘积为 W 2 W 1 = [ 3 1 0 2 ] W_2W_1=\begin{bmatrix}3&1\\0&2\end{bmatrix} W 2 W 1 = [ 3 0 1 2 ] 。此外,W 2 b 1 = ( − 3.5 , − 1 ) T W_2b_1=(-3.5,-1)^\mathsf{T} W 2 b 1 = ( − 3.5 , − 1 ) T ,因此加上 b 2 = ( 0.5 , − 1 ) T b_2=(0.5,-1)^\mathsf{T} b 2 = ( 0.5 , − 1 ) T 后,合并偏置为 ( − 3 , − 2 ) T (-3,-2)^\mathsf{T} ( − 3 , − 2 ) T 。结果仍具有 A x + c Ax+c A x + c 的形式,所以它是一个仿射映射。
Question 4
当 x = (1, 1)ᵀ 时,采用恒等隐藏步骤的版本会产生什么输出?与 ReLU 结果相比有何不同?
Show the step-by-step solution 采用恒等映射时,使用上一题得到的合并映射:[ 3 1 0 2 ] ( 1 , 1 ) T + ( − 3 , − 2 ) T = ( 1 , 0 ) T \begin{bmatrix}3&1\\0&2\end{bmatrix}(1,1)^\mathsf{T}+(-3,-2)^\mathsf{T}=(1,0)^\mathsf{T} [ 3 0 1 2 ] ( 1 , 1 ) T + ( − 3 , − 2 ) T = ( 1 , 0 ) T 。使用 ReLU 时,输出为 ( 1.5 , − 0.5 ) T (1.5,-0.5)^\mathsf{T} ( 1.5 , − 0.5 ) T ,因为第一个隐藏激活前值为负数并变为零,而第二个仍为 0.5 0.5 0.5 。差异来自逐坐标应用的激活函数。
Question 5
一个网络把 5 个输入映射到宽度为 3 的隐藏层,再映射到 4 个输出,中间没有激活函数。其线性部分的最大可能秩是多少?若第一个权重矩阵的秩为 2,第二个为 3 呢?
Show the step-by-step solution 组合矩阵经过三个隐藏坐标分解,因此其秩最多为三。它也不能超过输入维度五或输出维度四。如果第一个矩阵的秩为二,第二个矩阵的秩为三,则乘积的秩至多为这些上界中最小的值,即二。这些都是上界;如果方向彼此错位,实际乘积的秩还可能更低。
Question 6
在示例输入处,第一个 ReLU 单元未激活,第二个已激活。请计算局部雅可比矩阵的秩,并解释其含义。
Show the step-by-step solution 激活掩码为 D = diag ( 0 , 1 ) D=\operatorname{diag}(0,1) D = diag ( 0 , 1 ) 。相乘得到 J = W 2 D W 1 = [ 2 2 1 1 ] J=W_2DW_1=\begin{bmatrix}2&2\\1&1\end{bmatrix} J = W 2 D W 1 = [ 2 1 2 1 ] 。它的第二列与第一列相同,因此只有一个独立列,秩为一。在这个激活区域内,沿一个方向的小幅输入变化不会改变输出;两个分数都依赖相同的输入组合。这是局部结论,因为 ReLU 状态改变时矩阵 D D D 也会改变。
Question 7
当 ReLU 激活前值恰好为零时,会发生什么变化?能否把任一相邻区域的雅可比矩阵当作该点的单一导数?
Show the step-by-step solution ReLU 在零处有一个拐角:零的左侧斜率为零,右侧斜率为一。当激活前值恰好为零时,该坐标处的函数不可微,因此不存在一个能同时描述两侧的普通雅可比矩阵。网络输出仍然有定义;无法成立的是跨越边界的单一局部线性近似。
Question 8
一批数据有 8 个样本,每个样本有 4 个特征。对于 PyTorch Linear(4, 3),输入、输出形状和权重形状分别是什么?
Show the step-by-step solution 批次输入形状为 ( 8 , 4 ) (8,4) ( 8 , 4 ) ,即八行、每行四个输入特征。PyTorch 保存的层权重形状为 ( out features , in features ) (\text{out features},\text{in features}) ( out features , in features ) ,因此权重为 ( 3 , 4 ) (3,4) ( 3 , 4 ) ,偏置形状为 ( 3 , ) (3,) ( 3 , ) 。该层返回 ( 8 , 3 ) (8,3) ( 8 , 3 ) ,保留批次维度,并将最后一个特征维度替换为三个输出。
查看完整的 180 天课程