【问题标题】:Vectorized softmax gradient矢量化 softmax 梯度
【发布时间】:2020-04-04 19:14:14
【问题描述】:

我有一个 softmax 层(只有激活本身,没有将输入乘以权重的线性部分),我想为它做一个反向传递。

我在 SO 上找到了许多处理它的教程/答案,但它们似乎都使用 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 矩阵,这对于以下反向传播没有意义......正确的写法是什么?

【问题讨论】:

    标签: python numpy backpropagation


    【解决方案1】:

    我一直在处理同样的问题,最终找到了一种方法来向量化 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) 形状的数组,我认为它可以与np.matmul 函数一起用于反向传播,以正确地预乘您的dJ_dA 数组。

    需要注意的是,softmax 几乎只用作最后一层,并且通常带有交叉熵损失目标函数。在这种情况下,目标函数相对于 softmax 输入的导数可以更有效地找到为(S - Y)/m,其中m 是批次中的示例数,Y 是批次的标签,@987654329 @ 是你的 softmax 输出。这在下面的link中进行了解释。

    【讨论】:

      【解决方案2】:

      在编写我的 softmax 函数时,我发现这个问题非常有用:Softmax derivative in NumPy approaches 0 (implementation)。希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 2018-05-16
        • 1970-01-01
        • 1970-01-01
        • 2019-03-12
        • 2018-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多