我有一个softmax层(只有激活本身,没有将输入乘以权重的线性部分),我想让它成为一个反向传递。
我在上找到了很多关于它的教程/答案,但它们似乎都使用X
作为(1, n_inputs)
矢量。我想使用它作为(n_samples, n_inputs)
数组,并且仍然有一个正确的向前/向后传递的矢量化实现。
我已经编写了以下向前传递,对每一行/样本的输出进行标准化(是否正确?):
import numpy as np
X = np.asarray([
[0.0, 0.0],
[0.0, 1.0],
[1.0, 0.0],
[1.0, 1.0]], dtype=np.float32)
def prop(self, X):
s = np.exp(X)
s = s.T / np.sum(s, axis=1)
return s.T
它为我提供了前向传播(包括其他层)的最终结果:
Y = np.asarray([
[0.5 , 0.5 ],
[0.87070241, 0.12929759],
[0.97738616, 0.02261384],
[0.99200957, 0.00799043]], dtype=np.float32))
因此,这是softmax的输出,如果它是正确的。现在,我应该如何写向后传递?
我已经推导出softmax的导数为:
1)如果i=j
:p_i*(1 - p_j)
,
2)如果i!=j
:-p_i*p_j
,
哪里
我试着计算导数为:
ds = np.diag(Y.flatten()) - np.outer(Y, Y)
但是它导致了8x8矩阵,这对于下面的反向传播没有意义...正确的写法是什么?
发布于 2020-06-16 01:18:02
我一直在处理同样的问题,最终想出了一种方法来向量化softmax Jacobian的批量实现。这是我自己想出来的,所以我不确定这是不是最好的方法。这是我的想法:
import numpy as np
from scipy.special import softmax
def Jsoftmax(X):
sh = X.shape
sm = softmax(X, axis = 1)
DM = sm.reshape(sh[0],-1,1) * np.diag(np.ones(sh[1])) # Diagonal matrices
OP = np.matmul(sm.reshape(sh[0],-1,1), sm.reshape(sh[0],1,-1)) # Outer products
Jsm = DM - OP
return Jsm
它产生了一个(n_samples, n_inputs, n_inputs)
-shaped数组,我认为它可以通过np.matmul
函数在反向传播中使用,以正确地预乘dJ_dA
数组。
应该注意的是,softmax几乎完全用作最后一层,并且通常具有交叉进入损失目标函数。在这种情况下,目标函数相对于softmax输入的导数可以更有效地找到为(S - Y)/m
,其中m
是批次中的示例数量,Y
是批次的标签,S
是softmax输出。这在下面的link中进行了解释。
发布于 2019-12-12 06:50:14
在编写softmax函数时,我发现这个问题非常有用:Softmax derivative in NumPy approaches 0 (implementation)。希望能有所帮助。
https://stackoverflow.com/questions/59286911
复制相似问题