欢迎Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。
激活函数
我使用 relu.md 来阐述激活函数 ReLU 的主要思想。
概述
在机器学习领域,工程师可以自由选择任何可微分函数作为激活函数。在神经网络中引入非线性元素 ( f N N f_{NN} fNN) 对于模拟非线性现象至关重要。在缺乏激活函数的情况下, f N N f_{NN} fNN 的输出始终保持线性,不受其深度的影响,这是因为方程 A ⋅ W + b A · W + b A⋅W+b 的固有线性性质。
激活函数可以接受标量或向量参数。标量激活函数将函数应用于单个数字。标量激活函数分别应用于向量的每个元素,保持每个输入及其相应输出之间的直接关系,从而简化导数的计算。常见的标量激活函数选择包括 Sigmoid、ReLU、Tanh 和 GELU,如下图所示。
标量激活函数
如果激活函数逐元素地应用于 Z Z Z 的每个单独元素,独立处理每个 z i j z_{ij} zij,那么它就是一个标量激活函数。例如,将 ReLU 函数应用于 Z Z Z 的每个元素将是一个标量操作:
示例:
ReLU ( Z ) = ( max ( 0 , z 11 ) max ( 0 , z 12 ) max ( 0 , z 21 ) max ( 0 , z 22 ) max ( 0 , z 31 ) max ( 0 , z 32 ) ) \text{ReLU}(Z) = \begin{pmatrix} \max(0, z_{11}) & \max(0, z_{12}) \\ \max(0, z_{21}) & \max(0, z_{22}) \\ \max(0, z_{31}) & \max(0, z_{32}) \end{pmatrix} ReLU(Z)= max(0,z11)max(0,z21)max(0,z31)max(0,z12)max(0,z22)max(0,z32)
在这种情况下,每个元素 z i j z_{ij} zij 被独立处理,输出矩阵的形状与 Z Z Z 相同,但激活函数(在本例中为 ReLU)应用于每个元素。
导数简化
在像 ReLU 这样的标量激活函数中的一一对应关系简化了导数计算:
- 对于 x 1 = − 1 x1 = -1 x1=−1,导数 R e L U ′ ( x 1 ) = 0 ReLU'(x1) = 0 ReLU′(x1)=0,因为 x 1 x1 x1 是负数。
- 对于 x 2 = 5 x2 = 5 x2=5,导数 R e L U ′ ( x 2 ) = 1 ReLU'(x2) = 1 ReLU′(x2)=1,因为 x 2 x2 x2 是正数。
- 对于 x 3 = − 3 x3 = -3 x3=−3,导数 R e L U ′ ( x 3 ) = 0 ReLU'(x3) = 0 ReLU′(x3)=0,由于 x 3 x3 x3 是负数。
这种逐元素的方法允许直接计算导数,这是通过反向传播进行神经网络优化的关键方面。
逐元素导数
术语 “逐元素导数” 指的是针对函数输出的每个元素与其对应的输入元素独立计算的导数。这个概念广泛应用于应用于向量或矩阵的函数,例如神经网络中的激活函数。
当计算激活函数输出 A A A 相对于其输入 Z Z Z 的逐元素导数时,我们针对输出矩阵 A A A 中的每个条目 a i j a_{ij} aij 分别计算其对应的输入矩阵 Z Z Z 中的条目 z i j z_{ij} zij 的导数,其中 i i i 和 j j j 分别表示行和列索引。
通过示例进行说明
考虑一个简单的示例,使用一个向量输入和 ReLU 激活函数,定义为 ReLU ( x ) = max ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x)。
对于一个输入向量 Z = [ z 1 , z 2 , z 3 ] Z = [z_1, z_2, z_3] Z=[z1,z2,z3],ReLU 函数产生一个输出向量 A = [ a 1 , a 2 , a 3 ] A = [a_1, a_2, a_3] A=[a1,a2,a3],其中 a i = max ( 0 , z i ) a_i = \max(0, z_i) ai=max(0,zi),对于 i = 1 , 2 , 3 i = 1, 2, 3 i=1,2,3。
A A A 相对于 Z Z Z 的逐元素导数为:
∂ A ∂ Z = [ ∂ a 1 ∂ z 1 , ∂ a 2 ∂ z 2 , ∂ a 3 ∂ z 3 ] \frac{\partial A}{\partial Z} = \left[ \frac{\partial a_1}{\partial z_1}, \frac{\partial a_2}{\partial z_2}, \frac{\partial a_3}{\partial z_3} \right] ∂Z∂A=[∂z1∂a1,∂z2∂a2,∂z3∂a3]
对于 ReLU 函数,当 z i > 0 z_i > 0 zi>0 时,这个导数为 1(表示 z i z_i zi 的微小增加导致 a i a_i ai 的相等增加),当 z i ≤ 0 z_i \leq 0 zi≤0 时,导数为 0,因为 a i a_i ai 保持为 0 0 0,不受 z i z_i zi 变化的影响。
在神经网络中的重要性
在神经网络的背景下,特别是在反向传播过程中,逐元素导数在权重更新中发挥着关键作用。它使网络能够理解每个权重的微小变化如何影响总体损失,从而使梯度下降算法能够有效地最小化损失函数。这种个性化的计算确保了每个权重基于其对网络性能的特定贡献而进行优化。
向量激活函数
另一方面,像 Softmax 这样的向量激活函数涉及到输出与所有输入元素之间的相互依赖关系,使得导数计算过程变得复杂。如果激活函数将 Z Z Z 的每一行(或列)作为一个整体向量进行处理,并考虑该向量中元素之间的关系,那么它就是一个向量激活函数。一个例子是将 Softmax 函数应用于 Z Z Z 的每一行,将每一行视为多类分类问题的对数几率向量。
示例:
考虑一个具有对数几率为 Z = [ 2 , 1 , − 1 ] Z = [2, 1, -1] Z=[2,1,−1] 的 3 类分类问题的神经网络输出。应用 Softmax 函数会产生以下概率:
- Softmax ( z 1 ) = e 2 e 2 + e 1 + e − 1 \text{Softmax}(z_1) = \frac{e^2}{e^2 + e^1 + e^{-1}} Softmax(z1)=e2+e1+e−1e2
- Softmax ( z 2 ) = e 1 e 2 + e 1 + e − 1 \text{Softmax}(z_2) = \frac{e^1}{e^2 + e^1 + e^{-1}} Softmax(z2)=e2+e1+e−1e1
- Softmax ( z 3 ) = e − 1 e 2 + e 1 + e − 1 \text{Softmax}(z_3) = \frac{e^{-1}}{e^2 + e^1 + e^{-1}} Softmax(z3)=e2+e1+e−1e−1
每个输出概率都依赖于所有输入对数几率,显示了向量激活函数的相互关联性。
导数复杂性:
Softmax 函数相对于任何输入 z k z_k zk 的导数涉及到偏导数,其中每个输出都依赖于所有输入。这是由于分母中的归一化项包含所有输入的指数项。
例如,Softmax 函数相对于 z i z_i zi 的导数为:
- 如果 i = k i = k i=k: ∂ Softmax ( z i ) ∂ z k = Softmax ( z i ) ⋅ ( 1 − Softmax ( z k ) ) \frac{\partial \text{Softmax}(z_i)}{\partial z_k} = \text{Softmax}(z_i) \cdot (1 - \text{Softmax}(z_k)) ∂zk∂Softmax(zi)=Softmax(zi)⋅(1−Softmax(zk))
- 如果 i ≠ k i \neq k i=k: ∂ Softmax ( z i ) ∂ z k = − Softmax ( z i ) ⋅ Softmax ( z k ) \frac{\partial \text{Softmax}(z_i)}{\partial z_k} = -\text{Softmax}(z_i) \cdot \text{Softmax}(z_k) ∂zk∂Softmax(zi)=−Softmax(zi)⋅Softmax(zk)
这反映了一个对数几率的增加不仅增加了其对应的概率(假设它是正的),而且由于分母中的共享总和,还会降低其他类别的概率。
这种相互关联性使得像 Softmax 这样的向量激活函数的导数计算相比于像 ReLU 这样的标量激活函数更加复杂。
实现
-
类属性:
- 激活函数没有可训练的参数。
- 正向传播期间存储的变量,用于反向传播期间计算导数:层输出 A A A。
-
类方法:
-
f o r w a r d forward forward:前向方法接收一批数据 Z Z Z,其形状为 N × C N \times C N×C(代表有 N N N 个样本,每个样本有 C C C 个特征),并将激活函数应用于 Z Z Z 以计算形状为 N × C N \times C N×C 的输出 A A A。
-
b a c k w a r d backward backward:反向方法接收 d L d A dLdA dLdA,即后激活(输出)对损失的影响度量。使用这个以及激活函数自身的导数,该方法计算并返回 d L d Z dLdZ dLdZ,即前激活特征(输入) Z Z Z 的变化如何影响损失 L L L。对于标量激活, d L d Z dLdZ dLdZ 的计算为:
d L d Z = d L d A ⊙ ∂ A ∂ Z dLdZ = dLdA \odot \frac{\partial A}{\partial Z} dLdZ=dLdA⊙∂Z∂A
前向示例:
为了用一个例子说明这一点,让我们考虑一个简单的情况,我们有 3 个样本的批次( N = 3 N = 3 N=3)和每个样本有 2 个特征( C = 2 C=2 C=2)。所以,我们的输入矩阵 Z Z Z 可能看起来像这样:
-
Z = ( z 11 z 12 z 21 z 22 z 31 z 32 ) Z = \begin{pmatrix} z_{11} &z_{12} \\ z_{21} &z_{22} \\ z_{31} &z_{32} \end{pmatrix} Z= z11z21z31z12z22z32
应用 ReLU 激活函数,定义为 R e L U ( x ) = max ( 0 , x ) ReLU(x) = \max(0, x) ReLU(x)=max(0,x),我们得到输出矩阵 A A A 如下:
A = ( max ( 0 , z 11 ) max ( 0 , z 12 ) max ( 0 , z 21 ) max ( 0 , z 22 ) max ( 0 , z 31 ) max ( 0 , z 32 ) ) A = \begin{pmatrix} \max(0, z_{11}) & \max(0, z_{12}) \\ \max(0, z_{21}) &\max(0, z_{22}) \\ \max(0, z_{31}) &\max(0, z_{32}) \end{pmatrix} A= max(0,z11)max(0,z21)max(0,z31)max(0,z12)max(0,z22)max(0,z32)
如你所见, Z Z Z 中的每个元素都单独转换以产生 A A A 中的一个元素,但矩阵的整体形状,在这种情况下为 3 × 2 3 \times 2 3×2,保持不变。
使用 ReLU 激活的反向方法示例
让我们探索使用 ReLU(修正线性单元)激活函数的神经网络中反向方法的一个例子。ReLU 函数定义为 R e L U ( x ) = max ( 0 , x ) ReLU(x) = \max(0, x) ReLU(x)=max(0,x)。
前向传递
假设我们有一个神经元,它接收输入 Z Z Z 并应用 ReLU 激活函数以产生输出 A A A。考虑在前向传递期间单个输入值 Z = − 2 Z = -2 Z=−2:
A = R e L U ( Z ) = max ( 0 , − 2 ) = 0 A = ReLU(Z) = \max(0, -2) = 0 A=ReLU(Z)=max(0,−2)=0
反向传递
在反向传递期间,我们计算 d L d Z dLdZ dLdZ,它代表 Z Z Z(前激活输入)的变化如何影响损失 L L L,使用 d L d A dLdA dLdA(损失对激活函数输出的梯度)和激活函数的导数 ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A。
ReLU 函数相对于其输入 Z Z Z 的导数为:
∂ A ∂ Z = { 1 if Z > 0 0 otherwise \frac{\partial A}{\partial Z} = \begin{cases} 1 & \text{if } Z > 0 \\ 0 & \text{otherwise} \end{cases} ∂Z∂A={10if Z>0otherwise
对于 Z = − 2 Z = -2 Z=−2,导数 ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A 为 0 0 0,因为 Z Z Z 不大于 0 0 0。
假设反向传递给我们 d L d A = 0.5 dLdA = 0.5 dLdA=0.5,表示后激活输出 A A A 如何影响损失 L L L。
计算 d L d Z dLdZ dLdZ
要找到 d L d Z dLdZ dLdZ,我们使用:
d L d Z = d L d A ⊙ ∂ A ∂ Z dLdZ = dLdA \odot \frac{\partial A}{\partial Z} dLdZ=dLdA⊙∂Z∂A
代入已知值:
d L d Z = 0.5 ⊙ 0 = 0 dLdZ = 0.5 \odot 0 = 0 dLdZ=0.5⊙0=0
这个结果意味着在这种情况下,ReLU 函数将负输入夹紧到 0 0 0, Z Z Z 的变化对损失没有影响,如 d L d Z = 0 dLdZ = 0 dLdZ=0 所反映。这是直观的,因为对于 ReLU 的负输入,输出总是 0 0 0,并且 Z Z Z 的轻微变化不影响 A A A 或损失。
这个例子演示了使用反向方法和标量激活函数计算损失关于前激活输入的梯度。
对于 d L d Z = d L d A ⊙ ∂ A ∂ Z dLdZ = dLdA \odot \frac{\partial A}{\partial Z} dLdZ=dLdA⊙∂Z∂A,这里, ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A 表示激活输出 A A A 关于其对应输入 Z Z Z 的逐元素导数。具体地,对于大小为 1 × C 1 \times C 1×C 的单个输入,此导数等同于雅可比矩阵的对角线,表达为大小为 1 × C 1 \times C 1×C 的向量。这个概念与讲座中提出的理解一致,即标量激活函数的雅可比表现为对角矩阵。当考虑大小为 N N N 的批次时, ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A 的维度扩展为 N × C N \times C N×C。 ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A 的计算在不同的标量激活函数之间有所不同,如各自的小节中详细介绍的。 ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A 的大小是 N × C N \times C N×C,因为我们对每个样本的每个特征都有一个导数值。
理解标量激活函数的雅可比矩阵对角线
为了理解为什么对于一个大小为 1 × C 1 \times C 1×C 的单一输入,导数 ∂ A ∂ Z \frac{\partial A}{\partial Z} ∂Z∂A 等同于雅可比矩阵的对角线,我们需要探究激活函数上下文中雅可比矩阵的性质。
激活函数中的雅可比矩阵
雅可比矩阵代表了从 R n \mathbb{R}^n Rn 到 R m \mathbb{R}^m Rm 映射的函数的所有一阶偏导数。对于向量值函数 f ( x ) \mathbf{f}(\mathbf{x}) f(x),其中 x ∈ R n \mathbf{x} \in \mathbb{R}^n x∈Rn 且 f ( x ) ∈ R m \mathbf{f}(\mathbf{x}) \in \mathbb{R}^m f(x)∈Rm,雅可比矩阵 J J J 定义为:
J = ( ∂ f 1 ∂ x 1 ⋯ ∂ f 1 ∂ x n ⋮ ⋱ ⋮ ∂ f m ∂ x 1 ⋯ ∂ f m ∂ x n ) J = \begin{pmatrix} \frac{\partial f_1}{\partial x_1} & \cdots & \frac{\partial f_1}{\partial x_n} \\ \vdots & \ddots & \vdots \\ \frac{\partial f_m}{\partial x_1} & \cdots & \frac{\partial f_m}{\partial x_n} \end{pmatrix} J= ∂x1∂f1⋮∂x1∂fm⋯⋱⋯∂xn∂f1⋮∂xn∂fm
标量激活函数和雅可比矩阵
当标量激活函数如 ReLU 或 Sigmoid 逐元素应用于向量 z = [ z 1 , … , z C ] \mathbf{z} = [z_1, \ldots, z_C] z=[z1,…,zC] 时,它们可以被视为一组独立的标量函数 f i ( z i ) f_i(z_i) fi(zi)。在这种情况下,雅可比矩阵具有独特的结构。
ReLU 激活函数的示例
考虑将 ReLU 激活函数应用于输入向量 z = [ z 1 , z 2 , z 3 ] \mathbf{z} = [z_1, z_2, z_3] z=[z1,z2,z3](对于 C = 3 C = 3 C=3)。ReLU 函数将 z \mathbf{z} z 转换为 A = [ R e L U ( z 1 ) , R e L U ( z 2 ) , R e L U ( z 3 ) ] \mathbf{A} = [ReLU(z_1), ReLU(z_2), ReLU(z_3)] A=[ReLU(z1),ReLU(z2),ReLU(z3)]。
R e L U ( z ) ReLU(z) ReLU(z) 相对于 z z z 的导数为:
∂ R e L U ( z ) ∂ z = { 1 , if z > 0 0 , otherwise \frac{\partial ReLU(z)}{\partial z} = \begin{cases} 1, & \text{if } z > 0 \\ 0, & \text{otherwise} \end{cases} ∂z∂ReLU(z)={1,0,if z>0otherwise
对于一个所有元素均为正的输入向量 z \mathbf{z} z, A \mathbf{A} A 相对于 z \mathbf{z} z 的雅可比矩阵为:
J = ( 1 0 0 0 1 0 0 0 1 ) J = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix} J= 100010001
为什么是对角线?
对于逐元素的标量激活,雅可比矩阵的对角线性质产生是因为每个输出元素 A i A_i Ai 仅依赖于相应的输入元素 z i z_i zi,使得所有非对角线元素(代表输出相对于不同输入的导数)为零。位于对角线上的非零元素代表每个输出相对于其对应输入的导数,这简化了神经网络中的计算,特别是在反向传播期间。
理解向量激活函数的雅可比矩阵对角线
向量激活函数的雅可比矩阵不是对角矩阵。对于每个大小为 1 × C 1 \times C 1×C 的输入向量 Z ( i ) Z^{(i)} Z(i) 及其相应的输出向量 A ( i ) A^{(i)} A(i)(在批次中也是 1 × C 1 \times C 1×C),必须单独计算雅可比矩阵 J ( i ) J^{(i)} J(i)。这个矩阵的维度是 C × C C \times C C×C。因此,批次中每个样本的梯度 d L d Z ( i ) dLdZ^{(i)} dLdZ(i) 由下式确定:
d L d Z ( i ) = d L d A ( i ) ⋅ J ( i ) dLdZ^{(i)} = dLdA^{(i)} \cdot J^{(i)} dLdZ(i)=dLdA(i)⋅J(i)
计算每个 1 × C 1 \times C 1×C 向量 d L d Z ( i ) dLdZ^{(i)} dLdZ(i) 后,这些向量被垂直堆叠形成最终的 N × C N \times C N×C 矩阵 d L d Z dLdZ dLdZ,然后返回。
具体来说,向量值函数的雅可比矩阵代表了该函数的输出相对于其输入的所有一阶偏导数的集合。雅可比矩阵中的每个元素都是函数的一个输出分量相对于一个输入分量的偏导数。
在向量值函数 f ( x ) \mathbf{f}(\mathbf{x}) f(x) 的上下文中,其中 x \mathbf{x} x 是输入向量, f ( x ) \mathbf{f}(\mathbf{x}) f(x) 是输出向量,雅可比矩阵 J J J 定义为:
J = ( ∂ f 1 ∂ x 1 ⋯ ∂ f 1 ∂ x n ⋮ ⋱ ⋮ ∂ f m ∂ x 1 ⋯ ∂ f m ∂ x n ) J = \begin{pmatrix} \frac{\partial f_1}{\partial x_1} & \cdots & \frac{\partial f_1}{\partial x_n} \\ \vdots & \ddots & \vdots \\ \frac{\partial f_m}{\partial x_1} & \cdots & \frac{\partial f_m}{\partial x_n} \end{pmatrix} J= ∂x1∂f1⋮∂x1∂fm⋯⋱⋯∂xn∂f1⋮∂xn∂fm
这里, f 1 , f 2 , … , f m f_1, f_2, \ldots, f_m f1,f2,…,fm 是输出向量 f ( x ) \mathbf{f}(\mathbf{x}) f(x) 的分量, x 1 , x 2 , … , x n x_1, x_2, \ldots, x_n x1,x2,…,xn 是输入向量 x \mathbf{x} x 的分量。 J J J 中第 i i i 行第 j j j 列的元素 ∂ f i ∂ x j \frac{\partial f_i}{\partial x_j} ∂xj∂fi 代表第 i i i 个输出分量相对于第 j j j 个输入分量的偏导数。
总之,雅可比矩阵本身是一个导数矩阵,描述了输出向量的每个分量如何随输入向量的每个分量的变化而变化。它不是输入,而是一个描述输出对输入变化的敏感度的数学对象。
在神经网络中使用 Softmax 激活函数的示例
考虑一个神经网络层,批次中有 2 个样本( N = 2 N=2 N=2),每个样本有 3 个特征( C = 3 C=3 C=3)。这种设置可以代表分类问题中 3 个类的对数值。
我们的输入向量批次 Z Z Z 给定为:
Z = ( Z ( 1 ) Z ( 2 ) ) = ( 1 2 3 2 2 1 ) Z = \begin{pmatrix} Z^{(1)} & Z^{(2)} \end{pmatrix} = \begin{pmatrix} 1 & 2 & 3 \\ 2 & 2 & 1 \end{pmatrix} Z=(Z(1)Z(2))=(122231)
应用 Softmax 激活
Softmax 被应用于每个样本 Z ( i ) Z^{(i)} Z(i) 以产生输出向量 A ( i ) A^{(i)} A(i)。向量 Z ( i ) Z^{(i)} Z(i) 中元素 z j z_j zj 的 Softmax 函数定义为:
Softmax ( z j ) = e z j ∑ k = 1 C e z k \text{Softmax}(z_j) = \frac{e^{z_j}}{\sum\limits_{k=1}^{C} e^{z_k}} Softmax(zj)=k=1∑Cezkezj
将 Softmax 应用于 Z Z Z 的每一行后,我们得到:
A = ( A ( 1 ) A ( 2 ) ) = ( 0.09 0.24 0.67 0.42 0.42 0.16 ) A = \begin{pmatrix} A^{(1)} & A^{(2)} \end{pmatrix} = \begin{pmatrix} 0.09 & 0.24 & 0.67 \\ 0.42 & 0.42 & 0.16 \end{pmatrix} A=(A(1)A(2))=(0.090.420.240.420.670.16)
Softmax 的雅可比矩阵
对于 Softmax,单个样本 A ( i ) A^{(i)} A(i) 的雅可比矩阵 J ( i ) J^{(i)} J(i) 的元素为:
J j k ( i ) = { A j ( i ) ( 1 − A j ( i ) ) 如果 j = k − A j ( i ) A k ( i ) 其他情况 J^{(i)}_{jk} = \begin{cases} A^{(i)}_j (1 - A^{(i)}_j) & \text{如果 } j = k \\ -A^{(i)}_j A^{(i)}_k & \text{其他情况} \end{cases} Jjk(i)={Aj(i)(1−Aj(i))−Aj(i)Ak(i)如果 j=k其他情况
对于我们的第一个样本 A ( 1 ) A^{(1)} A(1),雅可比矩阵 J ( 1 ) J^{(1)} J(1) 将是一个 3x3 矩阵,其中每个元素使用上述规则计算。
计算 J ( 1 ) J^{(1)} J(1)
对于第一个样本, A ( 1 ) = [ 0.09 , 0.24 , 0.67 ] A^{(1)} = [0.09, 0.24, 0.67] A(1)=[0.09,0.24,0.67]。
使用 Softmax 导数公式:
当 j = k 时 : J j j ( 1 ) = A j ( 1 ) ( 1 − A j ( 1 ) ) 当 \ \ j = k 时: J^{(1)}_{jj} = A^{(1)}_j (1 - A^{(1)}_j) 当 j=k时:Jjj(1)=Aj(1)(1−Aj(1))
当
j
≠
k
时
:
J
j
k
(
1
)
=
−
A
j
(
1
)
A
k
(
1
)
当 \ \ j \neq k 时: J^{(1)}_{jk} = -A^{(1)}_j A^{(1)}_k
当 j=k时:Jjk(1)=−Aj(1)Ak(1)
因此,我们有:
J 11 ( 1 ) = 0.09 × ( 1 − 0.09 ) = 0.0819 J^{(1)}_{11} = 0.09 \times (1 - 0.09) = 0.0819 J11(1)=0.09×(1−0.09)=0.0819
J 22 ( 1 ) = 0.24 × ( 1 − 0.24 ) = 0.1824 J^{(1)}_{22} = 0.24 \times (1 - 0.24) = 0.1824 J22(1)=0.24×(1−0.24)=0.1824
J 33 ( 1 ) = 0.67 × ( 1 − 0.67 ) = 0.2211 J^{(1)}_{33} = 0.67 \times (1 - 0.67) = 0.2211 J33(1)=0.67×(1−0.67)=0.2211
并且对于
j ≠ k j \neq k j=k
J 12 ( 1 ) = J 21 ( 1 ) = − 0.09 × 0.24 = − 0.0216 J^{(1)}_{12} = J^{(1)}_{21} = -0.09 \times 0.24 = -0.0216 J12(1)=J21(1)=−0.09×0.24=−0.0216
J
13
(
1
)
=
J
31
(
1
)
=
−
0.09
×
0.67
=
−
0.0603
J^{(1)}_{13} = J^{(1)}_{31} = -0.09 \times 0.67 = -0.0603
J13(1)=J31(1)=−0.09×0.67=−0.0603
J
23
(
1
)
=
J
32
(
1
)
=
−
0.24
×
0.67
=
−
0.1608
J^{(1)}_{23} = J^{(1)}_{32} = -0.24 \times 0.67 = -0.1608
J23(1)=J32(1)=−0.24×0.67=−0.1608
所以, J ( 1 ) J^{(1)} J(1) 是
J ( 1 ) = ( 0.0819 − 0.0216 − 0.0603 − 0.0216 0.1824 − 0.1608 − 0.0603 − 0.1608 0.2211 ) J^{(1)} = \begin{pmatrix} 0.0819 & -0.0216 & -0.0603 \\ -0.0216 & 0.1824 & -0.1608 \\ -0.0603 & -0.1608 & 0.2211 \end{pmatrix} J(1)= 0.0819−0.0216−0.0603−0.02160.1824−0.1608−0.0603−0.16080.2211
同样地
J
(
2
)
=
(
0.2436
−
0.1764
−
0.0672
−
0.1764
0.2436
−
0.0672
−
0.0672
−
0.0672
0.1344
)
J^{(2)} = \begin{pmatrix} 0.2436 & -0.1764 & -0.0672 \\ -0.1764 & 0.2436 & -0.0672 \\ -0.0672 & -0.0672 & 0.1344 \end{pmatrix}
J(2)=
0.2436−0.1764−0.0672−0.17640.2436−0.0672−0.0672−0.06720.1344
计算梯度
d
L
d
Z
(
i
)
dLdZ^{(i)}
dLdZ(i)
假设我们有批次激活输出对损失的梯度 dLdA 为:
d
L
d
A
=
(
0.1
−
0.2
0.1
−
0.1
0.3
−
0.2
)
dLdA= \begin{pmatrix} 0.1 & -0.2 & 0.1 \\ -0.1 & 0.3 & -0.2 \end{pmatrix}
dLdA=(0.1−0.1−0.20.30.1−0.2)
每个样本的梯度 d L d Z ( i ) dLdZ^{(i)} dLdZ(i) 通过将 d L d A dLdA dLdA 的相应行与雅可比矩阵 J ( i ) J^{(i)} J(i) 相乘来计算:
d L d Z ( i ) = d L d A ( i ) ⋅ J ( i ) dLdZ^{(i)} = dLdA^{(i)} \cdot J^{(i)} dLdZ(i)=dLdA(i)⋅J(i)
这个操作将对每个样本执行,然后将得到的向量 d L d Z ( 1 ) dLdZ^{(1)} dLdZ(1) 和 d L d Z ( 2 ) dLdZ^{(2)} dLdZ(2) 堆叠起来形成整个批次的最终梯度矩阵 d L d Z dLdZ dLdZ。
具体计算
由于 Softmax 导数的复杂性以及为了简洁,这里省略了 J ( 1 ) J^{(1)} J(1) 和 J ( 2 ) J^{(2)} J(2) 的每个元素的详细计算。然而,通常的过程包括:
分别使用 A ( 1 ) A^{(1)} A(1) 和 A ( 2 ) A^{(2)} A(2) 计算 J ( 1 ) J^{(1)} J(1) 和 J ( 2 ) J^{(2)} J(2)。
将 d L d A ( 1 ) = [ 0.1 , − 0.2 , 0.1 ] dLdA^{(1)} = [0.1, -0.2, 0.1] dLdA(1)=[0.1,−0.2,0.1] 与 J ( 1 ) J^{(1)} J(1) 相乘得到 d L d Z ( 1 ) dLdZ^{(1)} dLdZ(1)。
将 d L d A ( 2 ) = [ − 0.1 , 0.3 , − 0.2 ] dLdA^{(2)} = [-0.1, 0.3, -0.2] dLdA(2)=[−0.1,0.3,−0.2] 与 J ( 2 ) J^{(2)} J(2) 相乘得到 d L d Z ( 2 ) dLdZ^{(2)} dLdZ(2)。
将 d L d Z ( 1 ) dLdZ^{(1)} dLdZ(1) 和 d L d Z ( 2 ) dLdZ^{(2)} dLdZ(2) 垂直堆叠形成 d L d Z dLdZ dLdZ
这个例子说明了使用向量激活函数的层如何计算损失对输入的梯度的过程,其中输入在产生输出时的相互依赖性要求计算每个样本的完整雅可比矩阵。
考虑以下用于标量激活的类结构:
class Activation:
def forward(self, Z):
self.A = # TODO
return self.A
def backward(self, dLdA):
dAdZ = # TODO
dLdZ = # TODO
return dLdZ
代码名称 | 数学表示 | 类型 | 形状 | 含义 |
---|---|---|---|---|
N | N N N | 标量 | - | 批量大小 |
C | C C C | 标量 | - | 特征数量 |
Z | Z Z Z | 矩阵 | N × C N \times C N×C | 由 C C C 个特征表示的 N N N 个输入的批次 |
A | A A A | 矩阵 | N × C N \times C N×C | 由 C C C 个特征表示的 N N N 个输出的批次 |
dLdA | ∂ L ∂ A \frac{\partial L}{\partial A} ∂A∂L | 矩阵 | N × C N \times C N×C | 后激活特征变化如何影响损失 |
dLdZ | ∂ L ∂ Z \frac{\partial L}{\partial Z} ∂Z∂L | 矩阵 | N × C N \times C N×C | 前激活特征变化如何影响损失 |
激活函数的拓扑结构在图一中说明。为了理解其在更广泛的网络架构中的上下文,请参考图二。
注意:在本文档中,我们遵循特定的约定:
- Z Z Z 代表线性层的输出。
- A A A 表示线性层的输入。
在这个框架中, Z Z Z 源自前一个线性层的输出,而 A A A 作为输入供下一个线性层使用。例如,如果 f l f_l fl 表示第 l l l 层的激活函数,则连续层之间 A A A 和 Z Z Z 的关系由下式给出:
A l + 1 = f l ( Z l ) A_{l+1} = f_l(Z_l) Al+1=fl(Zl)
这个方程强调了,一层的输出
Z
Z
Z 在经过激活函数
f
l
f_l
fl 的变换后,成为下一层的输入
A
A
A。
注意:在反向传递中使用 dLdZ,因为它通过 Z Z Z 直接将损失与我们想要优化的参数(权重和偏置)联系起来,因为 Z = W ⋅ A p r e v + b Z = W \cdot A_{prev} + b Z=W⋅Aprev+b,然后由 A = f ( Z ) A = f(Z) A=f(Z),其中 f f f 是激活函数。
在标量激活的情况下, d L d Z dLdZ dLdZ 的计算如下:
d L d Z = d L d A ⊙ ∂ A ∂ Z dLdZ = dLdA \odot \frac{\partial A}{\partial Z} dLdZ=dLdA⊙∂Z∂A
在向量激活函数的情况下, d L d Z dLdZ dLdZ 的计算为:对于每个大小为 1 × C 1 \times C 1×C 的输入向量 Z ( i ) Z^{(i)} Z(i) 及其相应的输出向量 A ( i ) A^{(i)} A(i)(在批次中也是 1 × C 1 \times C 1×C),必须单独计算雅可比矩阵 J ( i ) J^{(i)} J(i)。这个矩阵的维度是 C × C C \times C C×C。因此,批次中每个样本的梯度 d L d Z ( i ) dLdZ^{(i)} dLdZ(i) 由下式确定:
d L d Z ( i ) = d L d A ( i ) ⋅ J ( i ) dLdZ^{(i)} = dLdA^{(i)} \cdot J^{(i)} dLdZ(i)=dLdA(i)⋅J(i)
参考资料:
- CMU_11785_深度学习导论