numpy : 计算 softmax 函数的导数

Posted

技术标签:

【中文标题】numpy : 计算 softmax 函数的导数【英文标题】:numpy : calculate the derivative of the softmax function 【发布时间】:2017-03-27 07:53:17 【问题描述】:

我试图用MNIST 在一个简单的三层神经网络中理解backpropagation

weightsbias 的输入层。标签是MNIST,所以它是10 类向量。

第二层是linear tranform。第三层是softmax activation,以概率形式获取输出。

Backpropagation 在每一步计算导数并将其称为梯度。

之前的图层将globalprevious 渐变附加到local gradient。我在计算 softmaxlocal 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,其中 W1b1 与从输入层到隐藏层的线性变换相关联,W2b2 与从隐藏层的线性变换相关联到输出层。 Z1Z2 是隐藏层和输出层的输入向量。 a1a2代表隐藏层和输出层的输出。 a2 是您的预测输出。 delta3delta2 是误差(反向传播),您可以看到损失函数相对于模型参数的梯度。

这是 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 函数的导数的主要内容,如果未能解决你的问题,请参考以下文章

激活函数汇总,包含公式求导过程以及numpy实现,妥妥的万字干货

python中的双重反导计算

02. 导数与梯度矩阵运算性质科学计算库numpy

在 python numpy 中实现 Relu 导数

一个numpy数组的softmax函数逐行

softmax函数python实现