numpy :计算 softmax 函数的导数
numpy : calculate the derivative of the softmax function
我正在尝试通过 MNIST
.
在一个简单的 3 层神经网络中理解 backpropagation
输入层 weights
和 bias
。标签是 MNIST
所以它是一个 10
class 向量。
第二层是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
时的导数进行了解释。这是我想出的一个简单的代码片段,希望能验证我的理解:
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
,它是一个向量。这个对吗?有没有更好的写法?
正如我所说,你有 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)
我假设您有一个 3 层 NN,其中 W1
、b1
与从输入层到隐藏层的线性变换以及 W2
、b2
与从隐藏层到输出层的线性变换相关联。 Z1
和Z2
是隐藏层和输出层的输入向量。 a1
和a2
代表隐藏层和输出层的输出。 a2
是您的预测输出。 delta3
和 delta2
是误差(反向传播),您可以看到损失函数相对于模型参数的梯度。
这是一个 3 层 NN(输入层,只有一个隐藏层和一个输出层)的一般场景。您可以按照上述过程计算梯度,这应该很容易计算!由于此 post 的另一个答案已经指出了您代码中的问题,因此我不再重复。
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函数。
我正在尝试通过 MNIST
.
backpropagation
输入层 weights
和 bias
。标签是 MNIST
所以它是一个 10
class 向量。
第二层是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
时的导数进行了解释。这是我想出的一个简单的代码片段,希望能验证我的理解:
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
,它是一个向量。这个对吗?有没有更好的写法?
正如我所说,你有 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)
我假设您有一个 3 层 NN,其中 W1
、b1
与从输入层到隐藏层的线性变换以及 W2
、b2
与从隐藏层到输出层的线性变换相关联。 Z1
和Z2
是隐藏层和输出层的输入向量。 a1
和a2
代表隐藏层和输出层的输出。 a2
是您的预测输出。 delta3
和 delta2
是误差(反向传播),您可以看到损失函数相对于模型参数的梯度。
这是一个 3 层 NN(输入层,只有一个隐藏层和一个输出层)的一般场景。您可以按照上述过程计算梯度,这应该很容易计算!由于此 post 的另一个答案已经指出了您代码中的问题,因此我不再重复。
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函数。