代码来自:https : //github.com/torch/nn/blob/master/lib/THNN/generic/LogSoftMax.c
我看不到这段代码如何计算到LogSoftMax模块输入的梯度wrt。我很困惑的是两个for循环在做什么。
for (t = 0; t < nframe; t++)
{
sum = 0;
gradInput_data = gradInput_data0 + dim*t;
output_data = output_data0 + dim*t;
gradOutput_data = gradOutput_data0 + dim*t;
for (d = 0; d < dim; d++)
sum += gradOutput_data[d];
for (d = 0; d < dim; d++)
gradInput_data[d] = gradOutput_data[d] - exp(output_data[d])*sum;
}
}
在前进时间,我们有(其中x =输入向量,y =输出向量,f = logsoftmax,i =第i个分量):
yi = f(xi)
= log( exp(xi) / sum_j(exp(xj)) )
= xi - log( sum_j(exp(xj)) )
计算f的雅可比式Jf时(第i行):
dyi/dxi = 1 - exp(xi) / sum_j(exp(xj))
对于与我不同的k:
dyi/dxk = - exp(xk) / sum_j(exp(xj))
这给Jf:
1-E(x1) -E(x2) -E(x3) ...
-E(x1) 1-E(x2) -E(x3) ...
-E(x1) -E(x2) 1-E(x3) ...
...
和 E(xi) = exp(xi) / sum_j(exp(xj))
如果我们将gradInput命名为梯度输入,而gradOutput命名为梯度输出,则反向传播给出(链式规则):
gradInputi = sum_j( gradOutputj . dyj/dxi )
这等效于:
gradInput = transpose(Jf) . gradOutput
最后给出第i个组件:
gradInputi = gradOutputi - E(xi) . sum_j( gradOutputj )
因此,第一个循环进行预计算sum_j( gradOutputj )
,最后一个循环进行上述计算,即grad的第i个分量。输入-除了1 / sum_j(exp(xj))
在Torch实现中缺少指数项之外(上面的演算可能听起来应该正确并解释了当前的实现),也应该仔细检查。
更新:缺少 1 / sum_j(exp(xj))
术语没有问题。由于jacobian是根据输出值计算的,并且由于此先前计算的输出正好是log-softmax分布,因此该分布的sum-exp为1:
sum_j(exp(outputj)) = sum_j(exp( log(exp(inputj) / sum_k(exp(inputk) ))
= sum_j( exp(inputj) / sum_k(exp(inputk) )
= 1
因此,无需在实现中明确显示该术语,它给出了(对于x =输出):
gradInputi = gradOutputi - exp(outputi) . sum_j( gradOutputj )
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句