numpy : 计算 softmax 函数的导数
Posted
技术标签:
【中文标题】numpy : 计算 softmax 函数的导数【英文标题】:numpy : calculate the derivative of the softmax function 【发布时间】:2017-03-27 07:53:17 【问题描述】:我试图用MNIST
在一个简单的三层神经网络中理解backpropagation
。
有weights
和bias
的输入层。标签是MNIST
,所以它是10
类向量。
第二层是linear tranform
。第三层是softmax activation
,以概率形式获取输出。
Backpropagation
在每一步计算导数并将其称为梯度。
之前的图层将global
或previous
渐变附加到local gradient
。我在计算 softmax
的 local gradient
时遇到问题
网上的一些资源解释了softmax及其衍生物,甚至给出了softmax本身的代码示例
def softmax(x):
"""Compute the softmax of vector x."""
exps = np.exp(x)
return exps / np.sum(exps)
关于何时i = j
和何时i != j
解释了导数。这是我想出的一个简单的代码 sn-p,希望能验证我的理解:
def softmax(self, x):
"""Compute the softmax of vector x."""
exps = np.exp(x)
return exps / np.sum(exps)
def forward(self):
# self.input is a vector of length 10
# and is the output of
# (w * x) + b
self.value = self.softmax(self.input)
def backward(self):
for i in range(len(self.value)):
for j in range(len(self.input)):
if i == j:
self.gradient[i] = self.value[i] * (1-self.input[i))
else:
self.gradient[i] = -self.value[i]*self.input[j]
那么self.gradient
就是local gradient
,它是一个向量。它是否正确?有没有更好的写法?
【问题讨论】:
这太不清楚了...您实际上要计算什么梯度? SM 是从 R^n 到 R^n 的映射,因此您可以定义 n^2 个偏导数 dSM[i]/dx[k]... @JulienBernu 我已经更新了这个问题。有什么想法吗? 【参考方案1】:正如我所说,你有n^2
偏导数。
如果你算一下,你会发现 dSM[i]/dx[k]
是 SM[i] * (dx[i]/dx[k] - SM[i])
所以你应该有:
if i == j:
self.gradient[i,j] = self.value[i] * (1-self.value[i])
else:
self.gradient[i,j] = -self.value[i] * self.value[j]
而不是
if i == j:
self.gradient[i] = self.value[i] * (1-self.input[i])
else:
self.gradient[i] = -self.value[i]*self.input[j]
顺便说一句,这可以更简洁地计算出来(矢量化):
SM = self.value.reshape((-1,1))
jac = np.diagflat(self.value) - np.dot(SM, SM.T)
【讨论】:
好的,这就是雅可比行列式? 我想我又断开了连接。 @wasi 的回答中的线性变换是隐藏层吗? 我想是的。请注意,大多数人认为最后的线性变换 + SM 只是一层。一般来说,一个层是一个线性变换,然后是一个非线性(sigmoid、tanh、SM、relu 或其他......) 在我看到的一些实现中,也使用了前向传播中softmax的输出值。在您的版本中并非如此,仅使用来自损失函数梯度的输入。我错过了什么还是这是完整的公式?【参考方案2】:我假设您有一个 3 层 NN,其中 W1
、b1
与从输入层到隐藏层的线性变换相关联,W2
、b2
与从隐藏层的线性变换相关联到输出层。 Z1
和 Z2
是隐藏层和输出层的输入向量。 a1
和a2
代表隐藏层和输出层的输出。 a2
是您的预测输出。 delta3
和 delta2
是误差(反向传播),您可以看到损失函数相对于模型参数的梯度。
这是 3 层 NN(输入层,只有一个隐藏层和一个输出层)的一般场景。您可以按照上面描述的过程来计算应该很容易计算的梯度!由于这篇文章的另一个答案已经指出了您代码中的问题,因此我不再重复。
【讨论】:
澄清一件事。如果我们从 z2 开始,即 z1 从未存在过,那是否会使其成为 2 层 NN?发生两次的线性变换使其成为 3 层 NN? 你能解释一下方程中层的名称吗?您的情况下的输入层是z1?有多少隐藏层,它们是什么? 太棒了!非常感谢!上帝保佑你,祝你在博士学习中好运! 我将更新这个我整理的库以匹配上述内容。 github.com/autojazari/xiaonet/blob/master/xiaonet.py 完成后将编辑问题 这里的损失函数是什么?【参考方案3】:np.exp
不稳定,因为它有 Inf。
所以你应该减去x
中的最大值。
def softmax(x):
"""Compute the softmax of vector x."""
exps = np.exp(x - x.max())
return exps / np.sum(exps)
如果x
是矩阵,请检查this notebook中的softmax函数。
【讨论】:
以上是关于numpy : 计算 softmax 函数的导数的主要内容,如果未能解决你的问题,请参考以下文章