原创|通俗易懂!详解Softmax及求导过程、Python实现、交叉熵


目录

  • 前言
  • 一、概率学解释
  • 二、Softmax求导
    • 1.向量微积分
    • 2.Softmax的导数
  • 三、Softmax的计算和稳定性
    • 1.Python实现Softmax
  • 三、Softmax层及其导数
  • 四、Softmax 和交叉熵损失
  • 五、注释

前言 本文是对一篇国外的讲解Softmax的文章的翻译。
Softmax函数的输入是一个N维的向量,向量元素是任意实数,输出也是一个N维的向量,但是有如下性质:
  1. 输出向量元素取值范围是(0, 1)
  2. 对输出向量的所有元素求和时,和为1
Softmax函数是这样一个映射S ( a ) : R N → R N S(a): \mathbb{R}^N \xrightarrow{} \mathbb{R}^N S(a):RN ?RN
S ( a ) : [ a 1 a 2 . . . a N ] → [ S 1 S 2 . . . S N ] S(a): \begin{bmatrix} a_1 \\ a_2 \\ ... \\ a_N\end{bmatrix} \xrightarrow{} \begin{bmatrix} S_1 \\ S_2 \\ ... \\ S_N \end{bmatrix} S(a):?????a1?a2?...aN??????? ??????S1?S2?...SN???????
并且对于每个元素,用的是如下公式
S j = e a j ∑ i = 1 N e a k , ? j ∈ 1... N S_j= \frac{e^{a_j}}{\sum_{i=1}^N e^{a_k}}, \forall_j \in 1...N Sj?=∑i=1N?eak?eaj??,?j?∈1...N
我们很容易看到, S j S_j Sj?永远是正数(因为式中全是对 e e e求幂),并且由于在分母中包含了分子与其它正数求和,所以 0 < S j < 1 00 举个例子,向量[1.0, 2.0, 3.0]通过Softmax变成了[0.09, 0.24, 0.67]。元素顺序不变,并且和为1。假如是[1.0, 2.0, 5.0]通过Softmax变成了[0.02, 0.05, 0.93],同样是顺序不变,且和为1。可以注意到,0.93比另外2个数字大很多,而且在和为1的情况下,0.93已经占了绝大多数。直观地来讲,Softmax函数是“温柔”版的最大值函数,不同的是,Softmax没有直接取一个最大值,而是将所有元素变成各自占100 % 100\% 100% 的不同比例,元素占比越大,Softmax最终的输出值就越大,当然其他元素得出的值就越小。[1]
一、概率学解释 Softmax的两个性质使得它非常适合用概率来解释,这也让Softmax在机器学习领域大有用途。在多分类任务中,我们希望给每个输入做一个标注,标注它属于每个类的概率是多大。
如果我们有N个类别,目标就是找到一个N维向量,每个元素代表这个样本是此类别的概率,这个向量元素求和是1。听起来是不是比较熟悉?
我们可以把Softmax解释成如下所示:
S j = P ( y = j ∣ a ) S_j=P(y=j|a) Sj?=P(y=j∣a)
其中, y y y代表输出的类别,范围是 1... N 1...N 1...N, a a a是一个N维向量。有一个最基础的例子就是在多分类逻辑回归中,我们会把一个输入向量 x x x和一个权重向量 w w w做点积,然后这个点积被输入到Softmax中去计算概率。这种结构后面会讲到
我们可以发现,从概率学角度看,Softmax用于模型参数的最大似然估计是最优的,但是这超出了本文范围,具体可以看Deep Learning的第5章。
二、Softmax求导 1.向量微积分 在开始对Softmax进行求导之前,我们先看看如何对向量求导。
Softmax本质上是一个向量函数,输入输出都是向量,换句话说,Softmax有多个输入和多个输出,所以我们不能直接就问“Softmax的导数是什么”,我们应该这么问:
  1. 在Softmax输出的向量中,我们要计算的是哪个元素的导数值?
  2. 别忘了Softmax的输入也是向量,有多个元素,所以我们是在关于哪个变量在求偏导呢?
如果你觉得这个听起来很复杂,不要担心,向量微积分就是用来干这事的!我们要找的是这些偏导数:
? S i ? a j ~\\ \frac{\partial{S_i}}{\partial{a_j}}\\?aj??Si??
这是 第 i 个 输 出 关 于 第 j 个 输 入 求 偏 导 第i个输出关于第j个输入求偏导 第i个输出关于第j个输入求偏导,我们把这个记作: D j S i D_jS_i Dj?Si?。
由于Softmax是R N → R N \mathbb{R}^N \xrightarrow{} \mathbb{R}^N RN ?RN的函数,如果整体求导,我们实际上求的是一个 雅 可 比 矩 阵 ( J a c o b i a nM a t r i x ) 雅可比矩阵(Jacobian \ Matrix) 雅可比矩阵(Jacobian Matrix):
D S = [ D 1 S 1 ? D N S 1 ? ? ? D N S 1 ? D N S N ] DS= \begin{bmatrix} D_1 S_1 & \cdots & D_N S_1 & \\ \vdots & \ddots & \vdots \\ D_N S_1 & \cdots & D_N S_N \end{bmatrix} DS=????D1?S1??DN?S1??????DN?S1??DN?SN??????
在机器学习的文章中,“梯度”常被用来代替“导数”。严格地说,“梯度”是仅针对于标量而定义的(比如机器学习中的损失函数),但对于像Softmax这样的向量函数来说,用“梯度”是不准确的,“雅可比矩阵”才是对向量函数的导数的名称,但是为了方便描述,大多数场合我也直接用“导数”来描述。
2.Softmax的导数 让我们开始计算D j S i ( 任 意 i 和 j ) D_jS_i(任意i和j) Dj?Si?(任意i和j):
D j S i = ? S i ? a j = ? e a j ∑ k = 1 N e a k ? a j \begin{aligned} D_jS_i &= \frac{\partial{S_i}}{\partial{a_j}} \\ &= \frac{\partial{ \frac{e^{a_j}}{\sum_{k=1}^N e^{a_k}}{} }}{\partial{a_j}} \end{aligned} Dj?Si??=?aj??Si??=?aj??∑k=1N?eak?eaj????
我们使用一下分式函数求导公式:
对 于 f ( x ) = g ( x ) h ( x )f ′ ( x ) = g ′ ( x ) h ( x ) ? h ′ ( x ) g ( x ) h 2 ( x ) 对于f(x)=\frac{g(x)}{h(x)} \\ ~\\ f'(x)=\frac{g'(x)h(x) - h'(x)g(x)}{h^2(x)} \\ 对于f(x)=h(x)g(x)? f′(x)=h2(x)g′(x)h(x)?h′(x)g(x)?
我们让g i = e a i , h i = ∑ k = 1 N e a k g_i=e^{a_i},h_i=\sum_{k=1}^Ne^{a_k} gi?=eai?,hi?=∑k=1N?eak? ,注意无论h i h_i hi? 关于哪个a j a_j aj? 求偏导结果都是e a j e^{a_j} eaj?,然而对于g i g_i gi? 却不是这样,g i g_i gi? 对a j a_j aj? 求偏导当且仅当i = j i=j i=j 的时候才是e a j e^{a_j} eaj? ,因为只有i = j i=j i=j 时g i g_i gi? 中才包含a j a_j aj? ,否则偏导就是 0。
回到D j S i D_jS_i Dj?Si? 的求导,为了简化, ∑ \sum ∑ 代表∑ k = 1 N e a k \sum_{k=1}^Ne^{a_k} ∑k=1N?eak?
如果i = j i=j i=j:
? exp ? ( a j ) ∑ k = 1 N exp ? ( a k ) ? a j = e a i ∑ ? e a j e a i ∑ 2= e a i ∑ ∑ ? e a j ∑= S i ( 1 ? S j ) \begin{aligned} \frac{\partial{ \frac{\exp(a_j)}{\sum_{k=1}^N \exp(a_k)}{} }}{\partial{a_j}} &= \frac{e^{a_i} \sum - e^{a_j}e^{a_i}}{\sum^2} \\ ~\\ &=\frac{e^{a_i}}{\sum} \frac{\sum - e^{a_j}}{\sum} \\ ~\\ &= S_i(1-S_j) \\ \end{aligned} ?aj??∑k=1N?exp(ak?)exp(aj?)???=∑2eai?∑?eaj?eai??=∑eai??∑∑?eaj??=Si?(1?Sj?)?
最终的式子用S i S_i Si? 自己表示了S i S_i Si? 自己的导数,当要求导的函数包含e x e^x ex 时,这是常用的一种技巧。
类似地,我们处理i ≠ j i\neq j i?=j 的情况:
? exp ? ( a j ) ∑ k = 1 N exp ? ( a k ) ? a j = 0 ? e a j e a i ∑ 2= ? e a j ∑ e a i ∑= ? S j S i \begin{aligned} \frac{\partial{ \frac{\exp(a_j)}{\sum_{k=1}^N \exp(a_k)}{} }}{\partial{a_j}} &= \frac{0 - e^{a_j}e^{a_i}}{\sum^2} \\ ~\\ &= - \frac{e^{a_j}}{\sum} \frac{e^{a_i}}{\sum} \\ ~\\ &= -S_j S_i \\ \end{aligned} ?aj??∑k=1N?exp(ak?)exp(aj?)???=∑20?eaj?eai??=?∑eaj??∑eai??=?Sj?Si??
总结一下:
f ( x ) = { S i ( 1 ? S j ) i = j ? S j S i i ≠ j f(x)=\left\{ \begin{aligned} & S_i(1-S_j) & i=j\\ & -S_j S_i & i\neq j \\ \end{aligned} \right. f(x)={?Si?(1?Sj?)?Sj?Si??i=ji?=j?
我比较喜欢这种分开的形式,但是如果有比程序员在公式表达方面更准确的人的话,那一定是数学家们。这就是为什么你会在不同文章里看到对同一个公式的不同表达,但都是等价的。最常见的就是用了克罗内克函数:
δ i j = { 1 i = j 0 i ≠ j \delta_{ij}=\left\{ \begin{aligned} & 1 & i=j\\ & 0 & i\neq j \\ \end{aligned} \right. δij?={?10?i=ji?=j?
合到一起就写成
D j S i = S i ( δ i j ? S j ) D_jS_i=S_i(\delta_{ij} - S_j) Dj?Si?=Si?(δij??Sj?)
这些公式说的都是同一件事,不同的文章还有其他一些写法:
  1. 用矩阵公式来表达,用I I I 代替δ \delta δ,I I I 代表单位矩阵,就是把δ \delta δ 用矩阵形式表示了。
  2. 用1 1 1 来表示克罗内克函数,也就是1 函 数 1函数 1函数, D j S i = S i ( 1 ( i = j ) ? S j ) D_jS_i=S_i(1(i=j) - S_j) Dj?Si?=Si?(1(i=j)?Sj?) ,此处的1 ( i = j ) 1(i=j) 1(i=j) 表示只有i = j i=j i=j 时函数值取1,否则取0。
这些简写形式在我们想计算更复杂的、基于Softmax的导数的其它导数的时候变得很有用,否则我们就需要每次都重述一遍,很麻烦。
三、Softmax的计算和稳定性 1.Python实现Softmax 代码如下
import numpy as np def softmax(x): """计算向量 x 的 softmax.""" exps = np.exp(x) return exps / np.sum(exps)

尝试一下吧:
In [146]: softmax([1, 2, 3]) Out[146]: array([ 0.09003057,0.24472847,0.66524096])

但是当我们输入比较大的数值时,会发生错误(溢出):
In [148]: softmax([1000, 2000, 3000]) Out[148]: array([ nan,nan,nan])

Numpy使用的浮点数的数值范围是有限的,对于float64,最大可表示数的数量级是1 0 308 10^{308} 10308 ,Softmax中的e x e^x ex 导致很容易溢出,即使x x x 看起来没多大。
避免这个问题的一个好方法是将输入归一化,使其不要太大或太小,通过观察,我们可以像下面这样使用任意常数C C C:
S j = e a j ∑ i = 1 N e a k = C e a j ∑ i = 1 N C e a k S_j = \frac{e^{a_j}}{\sum_{i=1}^N e^{a_k}} = \frac{Ce^{a_j}}{\sum_{i=1}^N Ce^{a_k}} Sj?=∑i=1N?eak?eaj??=∑i=1N?Ceak?Ceaj??
然后我们把C C C 放到指数上面,我们得到:
S j = e a j + l n ( C ) ∑ i = 1 N e a k + l n ( C ) S_j = \frac{e^{a_j+ln(C)}}{\sum_{i=1}^N e^{a_k+ln(C)}} Sj?=∑i=1N?eak?+ln(C)eaj?+ln(C)?
因为C C C 是任意数字,所以我们可以写成:
S j = e a j + D ∑ i = 1 N e a k + D ~\\ S_j = \frac{e^{a_j+D}}{\sum_{i=1}^N e^{a_k+D}}Sj?=∑i=1N?eak?+Deaj?+D?
其中D D D 是任意常数,这个公式和原本的S j S_j Sj? 是一样的,所以我们需要挑选一个D D D 使我们的计算在数值上更好(不要溢出)。一个比较好的选择就是对输入向量x x x 取其中的最大元素:
D = ? m a x ( a 1 , a 2 , ? ? , a N ) D=-max(a_1, a_2, \cdots, a_N) D=?max(a1?,a2?,?,aN?)
假设输入本身彼此之间不太远的话,这样可以把输入值全部“平移”到一个接近于零的范围。重要之处在于,这样把它们都变成了负数(当然最大的那个元素变成了0)。负的大指数会让式子的值最终变到0而不是无穷大,所以我们能更好地避免Nan。
代码如下
def stablesoftmax(x): """稳定的Softmax,防止溢出""" shiftx = x - np.max(x) exps = np.exp(shiftx) return exps / np.sum(exps)

现在代入数字试试:
In [150]: stablesoftmax([1000, 2000, 3000]) Out[150]: array([ 0.,0.,1.])

三、Softmax层及其导数 Softmax的常用于机器学习中,特别是在logistic回归中的Softmax层,我们将Softmax应用于完全连接层(矩阵乘法)的输出。
原创|通俗易懂!详解Softmax及求导过程、Python实现、交叉熵
文章图片



在这个图中,我们有一个有n n n 个特征的输入,和T T T 个可能的输出类。使用权值矩阵W W W 将x x x 转换为带有T T T 元素的向量(在机器学习中称为“Logits”),使用Softmax函数将Logits“坍塌”为一个概率向量,表示x x x 属于T T T 输出类中的每一个的概率。
我们如何计算这个“Softmax层”(全连接矩阵乘法后跟Softmax)的导数?当然是用链式法则!网上有很多关于这个公式的推导,但我想从基本原理入手,仔细地将多元链式法则应用到涉及到的函数的雅可比矩阵中。
在我们开始之前,有一点很重要:你可能认为x x x 是自变量,需要计算它的导数,但其实不是。事实上在机器学习中,我们要找到最优的权值矩阵W W W ,因此我们每一步梯度下降都要更新W W W ,因此,我们要计算这一层关于W W W 的导数。
我们先把这个式子写成向量函数的复合形式。首先我们做了一次矩阵乘法,记为g ( W ) g(W) g(W) ,因为输入是W N × T W_{N \times T} WN×T? 输出是T T T ,所以是这样的结果 : R N T → R T \mathbb{R}^{N T}\xrightarrow{} \mathbb{R}^T RNT ?RT
接下来是Softmax,如果我们把对数向量表示为λ \lambda λ ,我们就有S ( λ ) : R T → R T S(\lambda):\mathbb{R}^{T}\xrightarrow{} \mathbb{R}^T S(λ):RT ?RT 。
综上我们就有了一个复合函数:
P ( W ) = S ( g ( w ) ) = ( S ° g ) ( W ) \begin{aligned} P(W) &= S(g(w)) \\ &=(S \circ g)(W) \end{aligned} P(W)?=S(g(w))=(S°g)(W)?
应用链式法则,得到P ( W ) P(W) P(W) 的雅可比矩阵:
D g = [ D 1 g 1 ? D N T g 1 ? ? ? D 1 g T ? D N T g T ] Dg= \begin{bmatrix} D_1 g_1 & \cdots & D_{NT} g_1 & \\ \vdots & \ddots & \vdots \\ D_1 g_T & \cdots & D_{NT} g_T \end{bmatrix} Dg=????D1?g1??D1?gT??????DNT?g1??DNT?gT??????
在某种意义上,权值矩阵W W W 被 线性化(linearize) 为一个长度为N × T N \times T N×T 的向量,如果您熟悉多维数组在内存的样子,那么应该很容易理解它是如何实现的。在我们的例子中,我们可以做的就是按行(row)的顺序将其线性化,即第一行算在一起的,然后是第二行诸如此类。在数学上, W i j W_{ij} Wij? 将会得到雅可比矩阵中的第( i ? 1 ) N + j (i-1)N+j (i?1)N+j 列的数字,至于D g Dg Dg ,让我们回想一下g 1 g_1 g1?是什么:
g 1 = W 11 x 1 + W 12 x 2 + ? + W 1 N x N g1=W_{11}x_1 + W_{12}x_2 + \cdots + W_{1N}x_N g1=W11?x1?+W12?x2?+?+W1N?xN?
所以:
D 1 g 1 = x 1 D 2 g 1 = x 2 ? D N g 1 = x N D N + 1 g 1 = 0 D N T g 1 = 0 \begin{aligned} \\ D_1 g_1 &= x_1 \\ D_2 g_1 &= x_2 \\ \cdots \\ D_N g_1 &= x_N \\ D_{N+1} g_1 &= 0 \\ D_{NT} g_1 &= 0 \\ \end{aligned}\\ D1?g1?D2?g1??DN?g1?DN+1?g1?DNT?g1??=x1?=x2?=xN?=0=0?
如果我们用相同的办法计算g 2 ? g T g_2 \cdots g_T g2??gT? ,我们就得到了雅可比矩阵:
D g = [ x 1 x 2 ? x N ? 0 0 ? 0 ? ? ? ? ? ? ? ? ? 0 0 ? 0 ? x 1 x 2 ? x N ] Dg= \begin{bmatrix} x_1 & x_2 & \cdots & x_N & \cdots & 0 & 0 & \cdots & 0\\ \vdots & \ddots & \ddots & \ddots & \ddots & \ddots & \ddots & \ddots & \vdots \\ 0 & 0 & \cdots & 0 & \cdots & x_1 & x_2 & \cdots &x_N \end{bmatrix} Dg=????x1??0?x2??0?????xN??0?????0?x1??0?x2??????0?xN??????
换个角度看,如果我们按照W i j W_{ij} Wij? 分开看,就得到:
D i j g t = ? ( W t 1 x 1 + W t 2 x 2 + ? + W t N x N ) ? W i j = { x j i = t 0 i ≠ t ~\\ \begin{aligned} D_{ij} g_t &= \frac{\partial{(W_{t1}x_1 + W_{t2}x_2 + \cdots + W_{tN}x_N)}}{\partial{W_{ij}}} \\ &= \left\{ \begin{aligned} & x_j & i=t \\ & 0 & i \neq t \\ \end{aligned} \right. \end{aligned}Dij?gt??=?Wij??(Wt1?x1?+Wt2?x2?+?+WtN?xN?)?={?xj?0?i=ti?=t??
这一项对应的是雅可比矩阵的第t t t 行,第( i ? 1 ) N + j (i-1)N+j (i?1)N+j 列。
最终 D S DS DS 和D g Dg Dg 再做一次点积运算就得到了Softmax的完整的雅可比矩阵。注意P ( W ) : R N T → R T P(W): \mathbb{R}^{N T}\xrightarrow{} \mathbb{R}^T P(W):RNT ?RT 符合雅可比矩阵的维度,因为D S DS DS 是T × T T \times T T×T 的而且D g Dg Dg 是T × N T T \times NT T×NT ,所以它们点积就是T × N T T \times NT T×NT。
在文献中,你会看到Softmax层的导数的一个非常简短的推导。这很好,因为所涉及的两个函数简单且众所周知。如果我们仔细计算D S DS DS 内的一行和D g Dg Dg 内的一列的点积:
D i j P t = ∑ k = 1 T D k S t ? D i j g k D_{ij} P_t = \sum_{k=1}^T D_k S_t \cdot D_{ij} g_k Dij?Pt?=k=1∑T?Dk?St??Dij?gk?
D g Dg Dg 大部分是零,所以最终结果更简单。当且仅当i = k i=k i=k 时, D i j g k D_{ij} g_k Dij?gk? 才不是0,所以:
D i j P t = D i S t x j = S t ( δ t i ? S i ) x j \begin{aligned} \\ D_{ij} P_t &= D_i S_t x_j \\ &= S_t (\delta_{ti} - S_i) x_j \\ \end{aligned} \\ Dij?Pt??=Di?St?xj?=St?(δti??Si?)xj??
【原创|通俗易懂!详解Softmax及求导过程、Python实现、交叉熵】所以完全有可能计算Softmax层的导数而不需要实际的雅可比矩阵乘法,这避免了昂贵的矩阵乘法。由于全连接层的雅可比矩阵是稀疏的,这样就避免了大部分的计算。
也就是说,我仍然觉得很重要的一点是展示这个导数是如何从复合函数雅可比矩阵的基本原理中产生的。这种方法的优点是,它适用于更复杂的复合函数,更复杂的复合函数意味着其中每个元素的导数的“封闭形式”如果用其他方法计算要困难得多。
四、Softmax 和交叉熵损失 我们已经看到Softmax函数是如何被用作神经网络的一部分,以及如何使用多元链式法则来计算它的导数。我们同样有必要看看与Softmax一起用于训练网络的一个损失函数:交叉熵(Cross Entropy)
交叉熵有一个有趣的概率和信息理论解释,但这里我只关注他的运作特性。
对于两个离散的概率分布p p p 和q q q ,它们的交叉熵就是:
x e n t ( p , q ) = ? ∑ k p ( k ) l n ( q ( k ) ) xent(p,q) = - \sum_{k} p(k) ln(q(k)) xent(p,q)=?k∑?p(k)ln(q(k))
k k k 代表这个分布所定义的随机变量的所有可能值,在我们的例子中有T T T 个输出类,所以k = 1 , 2 ? T k=1,2 \cdots T k=1,2?T 。
如果我们从Softmax的输出P P P 开始,P P P 其实是一个概率分布[2],另一个概率分布是真实的分类输出(也就是标签Label),通常用Y Y Y 表示,Y Y Y 是一个1 × T 1 \times T 1×T 的one-hot向量,其中除了一个元素是1之外,所有元素都是0,值为1的元素表示模型预测的类别。
基于上面所述的情景,交叉熵损失公式就是:
x e n t ( Y , P ) = ? ∑ k = 1 T Y ( k ) l n ( P ( k ) ) xent(Y,P) = - \sum_{k=1}^T Y(k) ln(P(k)) xent(Y,P)=?k=1∑T?Y(k)ln(P(k))
k k k 代表所有可能的输出类, P ( k ) P(k) P(k) 为模型预测此输入属于这个类的概率, Y ( k ) Y(k) Y(k) 是真实情况下,此输入属于这个类别的概率。我们用y y y 标记Y ( k ) Y(k) Y(k) 中唯一的、值为1的元素的下标。因为k ≠ y k \neq y k?=y 时,Y ( k ) = 0 Y(k)=0 Y(k)=0 ,所以公式被化简为:
x e n t ( P ) = ? l n ( P ( k ) ) xent(P) = - ln(P(k)) xent(P)=?ln(P(k))
交叉熵的雅可比矩阵是一个1 × T 1 \times T 1×T 的行向量,由于输入的P P P 也是1 × T 1 \times T 1×T 的,故:
D x e n t ( P ) = [ D 1 x e n t D 2 x e n t ? D T x e n t ] Dxent(P) = \begin{bmatrix} D_1 xent & D_2 xent & \cdots & D_T xent \\ \end{bmatrix} Dxent(P)=[D1?xent?D2?xent???DT?xent?]
现在回想一下, P P P 可以用输入的权值表示: P ( W ) = S ( g ( W ) ) P(W)=S(g(W)) P(W)=S(g(W)),所以:
x e n t ( W ) = ( x e n t ° P ) ( W ) = x e n t ( P ( W ) ) xent(W) = (xent \circ P)(W) = xent(P(W)) xent(W)=(xent°P)(W)=xent(P(W))
我们可以再用链式法则来求xent的梯度:
D x e n t ( W ) = D ( x e n t ° P ) ( W ) = D x e n t ( P ( W ) ) ? D P ( W ) Dxent(W) = D(xent \circ P)(W) = Dxent(P(W)) \cdot DP(W) Dxent(W)=D(xent°P)(W)=Dxent(P(W))?DP(W)
我们来检验一下雅可比矩阵的维数是否成立。我们已经计算了D P ( W ) T × N T DP(W)_{T \times NT} DP(W)T×NT? 和D x e n t ( P ( W ) ) 1 × T Dxent(P(W))_{1 \times T} Dxent(P(W))1×T? 所以结果雅可比矩阵是D x e n t ( W ) 1 × N T Dxent(W)_{1 \times NT} Dxent(W)1×NT?,结果成立,因为整个网络只有一个标量值输出(交叉熵损失)以及一个N × T N \times T N×T 的权值输入W W W。
这里,有一个直接的方法化简D x e n t ( W ) Dxent(W) Dxent(W),因为矩阵乘法中的很多元素最终消去了。注意x e n t ( P ) xent(P) xent(P) 只依赖于P P P 的第y y y 个元素,所以整个雅可比矩阵只有D y x e n t ≠ 0 D_yxent \neq 0 Dy?xent?=0 :
D x e n t ( P ) = [ 0 0 D y x e n t ? 0 ] Dxent(P) = \begin{bmatrix} 0 & 0 & D_yxent & \cdots & 0 \\ \end{bmatrix} Dxent(P)=[0?0?Dy?xent???0?]
其中D y x e n t = ? 1 P y D_yxent = - \frac{1}{P_y} Dy?xent=?Py?1? 。
回到完整的雅可比矩阵,我们把D x e n t ( P ) Dxent(P) Dxent(P) 乘以D P ( W ) DP(W) DP(W) 的每一列来得到结果行向量中的每一个元素,回想一下,行向量表示整个权值矩阵W W W 以行主序被“线性化”。下面公式中D i j D_{ij} Dij? 表示行向量的第( i ? 1 ) N + j (i-1)N+j (i?1)N+j 个元素:
D i j x e n t ( W ) = ∑ k = 1 T D k x e n t ( P ) ? D i j P k ( W ) D_{ij}xent(W) = \sum_{k=1}^T D_k xent(P) \cdot D_{ij} P_k(W) Dij?xent(W)=k=1∑T?Dk?xent(P)?Dij?Pk?(W)
因为D k x e n t ( P ) D_k xent(P) Dk?xent(P) 只有第y y y 个元素是非零的,化简得到如下(代入上面化简的Softmax导数):
D i j x e n t ( W ) = D y x e n t ( P ) ? D i j P y ( W ) = ? 1 P y ? S y ( δ y i ? S i ) x j = ( S i ? δ y i ) x j \begin{aligned}\\ D_{ij}xent(W) &= D_y xent(P) \cdot D_{ij} P_y(W) \\ &= - \frac{1}{P_y} \cdot S_y (\delta_{yi} - S_i)x_j \\ &= (S_i - \delta_{yi})x_j \\ \end{aligned}\\ Dij?xent(W)?=Dy?xent(P)?Dij?Py?(W)=?Py?1??Sy?(δyi??Si?)xj?=(Si??δyi?)xj??
根据定义, P y = S y P_y=S_y Py?=Sy?,所以得到:
D i j x e n t ( W ) = ? 1 S y ? S y ( δ y i ? S i ) x j = ? ( δ y i ? S i ) x j = ( S i ? δ y i ) x j \begin{aligned}\\ D_{ij}xent(W) &= - \frac{1}{S_y} \cdot S_y (\delta_{yi} - S_i)x_j \\ &= - (\delta_{yi} - S_i)x_j \\ &= (S_i - \delta_{yi})x_j \\ \end{aligned}\\ Dij?xent(W)?=?Sy?1??Sy?(δyi??Si?)xj?=?(δyi??Si?)xj?=(Si??δyi?)xj??
再一次,即使在这种情况下,最终的结果是漂亮、干净,它不是必须这样,计算D i j x e n t ( W ) D_{ij}xent(W) Dij?xent(W) 的公式最终可能是一个相当复杂的求和(或求和的求和)。雅可比矩阵乘法的技巧也许用不上,因为计算机可以为我们做所有的求和,我们所要做的就是计算各个函数的雅可比矩阵,这通常比较简单因为它们用于更简单的非复合函数,这就是链式法则的魅力和效用。
五、注释
[1] 为了更好地使用示例输入和Softmax输出,Michael Nielsen的在线书籍有一个很好的交互式Javascript可视化。

[2] 花一点时间回顾一下,根据定义,Softmax函数的输出确实是有效的离散概率分布。

    推荐阅读