0

код приходит от: https://github.com/torch/nn/blob/master/lib/THNN/generic/LogSoftMax.cПытаясь понять код, который вычисляет градиент WRT на вход для LogSoftMax в Факеле

Я не вижу, как этот код вычисления градиента w.r.t к входу для модуля LogSoftMax. То, что я смущен, - это то, что делают два цикла.

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; 
} 
} 

ответ

3

В прямое время мы (с й = входным вектором, Y = выходной вектором, F = logsoftmax, I = I-й компонент):

yi = f(xi) 
    = log(exp(xi)/sum_j(exp(xj))) 
    = xi - log(sum_j(exp(xj))) 

При вычислении якобиана Jf Р у вас есть (я-я строка):

dyi/dxi = 1 - exp(xi)/sum_j(exp(xj)) 

И к различным, чем я:

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 Градиент входные данные WRT и gradOutput выход градиента орбиты относительно обратного распространения дает (правило цепи):

gradInputi = sum_j(gradOutputj . dyj/dxi) 

Это эквивалентно:

gradInput = transpose(Jf) . gradOutput 

Который, наконец, дает для г-го компонента:

gradInputi = gradOutputi - E(xi) . sum_j(gradOutputj) 

Таким образом, первый цикл предварительно вычисляет sum_j(gradOutputj) и последний выше термин, т.е. я-я компонента град. вход - за исключением отсутствия 1/sum_j(exp(xj)) для экспоненциального члена в реализации факела (вышеупомянутое исчисление должно быть проверено дважды, даже если оно звучит правильно и объясняет текущую реализацию).

UPDATE: нет никаких проблем с отсутствующего1/sum_j(exp(xj)) срок. Так как якобиан вычисляется на значение по вывода, так как это ранее вычисленный выход именно распределение лог-SoftMax речь идет о том, что сумма Экспоненциальная этого распределения не 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) 

 Смежные вопросы

  • Нет связанных вопросов^_^