如何独立于任何损耗函数实现Softmax导数?

dan*_*jar 12 regression derivative backpropagation neural-network softmax

对于神经网络库,我实现了一些激活函数和损失函数及其衍生物.它们可以任意组合,输出层的导数只是损耗导数和激活导数的乘积.

但是,我没有独立于任何损失函数实现Softmax激活函数的导数.由于归一化即等式中的分母,改变单个输入激活会改变所有输出激活而不仅仅是一个.

这是我的Softmax实现,其衍生物未通过梯度检查约1%.如何实现Softmax衍生产品以便与任何损耗功能相结合?

import numpy as np


class Softmax:

    def compute(self, incoming):
        exps = np.exp(incoming)
        return exps / exps.sum()

    def delta(self, incoming, outgoing):
        exps = np.exp(incoming)
        others = exps.sum() - exps
        return 1 / (2 + exps / others + others / exps)


activation = Softmax()
cost = SquaredError()

outgoing = activation.compute(incoming)
delta_output_layer = activation.delta(incoming) * cost.delta(outgoing)
Run Code Online (Sandbox Code Playgroud)

tic*_*cky 10

它应该是这样的:(x是softmax层的输入,dy是来自它上面的损失的delta)

    dx = y * dy
    s = dx.sum(axis=dx.ndim - 1, keepdims=True)
    dx -= y * s

    return dx
Run Code Online (Sandbox Code Playgroud)

但是你计算错误的方式应该是:

    yact = activation.compute(x)
    ycost = cost.compute(yact)
    dsoftmax = activation.delta(x, cost.delta(yact, ycost, ytrue)) 
Run Code Online (Sandbox Code Playgroud)

说明:因为delta函数是反向传播算法的一部分,所以它的职责是将向量dy(在我的代码中,outgoing在你的例子中)乘以在其中compute(x)计算的函数的雅可比行列式x.如果你弄清楚这个Jacobian对于softmax [1]看起来是什么样的,然后将它从左边乘以一个向量dy,经过一些代数后你就会发现你得到了与我的Python代码相对应的东西.

[1] https://stats.stackexchange.com/questions/79454/softmax-layer-in-a-neural-network


Aer*_*rin 7

数学上,Softmaxσ(j)相对于logit Zi的导数(例如,Wi*X)是

在此输入图像描述

其中红色三角洲是克罗内克三角洲.

如果迭代实现:

def softmax_grad(s):
    # input s is softmax value of the original input x. Its shape is (1,n) 
    # i.e.  s = np.array([0.3,0.7]),  x = np.array([0,1])

    # make the matrix whose size is n^2.
    jacobian_m = np.diag(s)

    for i in range(len(jacobian_m)):
        for j in range(len(jacobian_m)):
            if i == j:
                jacobian_m[i][j] = s[i] * (1 - s[i])
            else: 
                jacobian_m[i][j] = -s[i] * s[j]
    return jacobian_m
Run Code Online (Sandbox Code Playgroud)

测试:

In [95]: x
Out[95]: array([1, 2])

In [96]: softmax(x)
Out[96]: array([ 0.26894142,  0.73105858])

In [97]: softmax_grad(softmax(x))
Out[97]: 
array([[ 0.19661193, -0.19661193],
       [-0.19661193,  0.19661193]])
Run Code Online (Sandbox Code Playgroud)

如果您在矢量化版本中实现:

soft_max = softmax(x)    

# reshape softmax to 2d so np.dot gives matrix multiplication

def softmax_grad(softmax):
    s = softmax.reshape(-1,1)
    return np.diagflat(s) - np.dot(s, s.T)

softmax_grad(soft_max)

#array([[ 0.19661193, -0.19661193],
#       [-0.19661193,  0.19661193]])
Run Code Online (Sandbox Code Playgroud)

  • for jacobian_m [i] [j] = s [i]*(1-s [i])我得到错误TypeError:'numpy.float64'对象不支持项目赋值你如何解决这个numpy输入矩阵? (2认同)