7

Для библиотеки нейронных сетей я реализовал некоторые функции активации и функции потерь и их производные. Их можно комбинировать произвольно, а производная на выходных слоях просто становится произведением производной потерь и производной активации.Как реализовать производную 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) 

ответ

3

Математически, производная от SoftMax (Xi) по отношению к Xj является:

enter image description here

где красная дельта дельта Кронекера.

Если вы реализуете итеративно:

def softmax_grad(s): 
    # input s is softmax value of the original input x. Its shape is (1,n) 
    # e.i. 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 

Тест:

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]]) 

Если вы реализуете в векторизованной версии:

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]]) 
+0

для jacobian_m [i] [j] = s [i] * (1-s [i]) Я получаю ошибку TypeError: объект 'numpy.float64' не поддерживает назначение элемента, как бы вы исправить это для матрицы ввода numpy ? –

10

Это должно быть так: (х вход в SoftMax слой и диспрозия дельта идет от потери над ним)

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

    return dx 

Но, как вы вычислить погрешность должна быть :

yact = activation.compute(x) 
    ycost = cost.compute(yact) 
    dsoftmax = activation.delta(x, cost.delta(yact, ycost, ytrue)) 

Объяснение: Поскольку функция delta является частью алгоритма обратного распространения, его обязанность заключается в том, чтобы умножить вектор dy (в моем код, outgoing в вашем случае) якобианом функции compute(x), оцененной в x. Если вы выясните, что делает этот якобиан для softmax [1], а затем умножьте его слева на вектор dy, после бит алгебры вы узнаете, что получаете что-то, что соответствует моему коду Python.

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

+0

Спасибо за ваш ответ. На что вы ссылаетесь 'res'? – danijar

+0

Я имел в виду dx (я вручную реорганизовал код для этого ответа и забыл об этом возникновении кода =)). Я исправил это в ответе. – ticcky

+0

Ваше решение отлично подходит для меня. Проходят градиентные проверки. Из любопытства вы могли бы кратко объяснить, как вы пришли к формуле? Я бы очень хотел это понять. – danijar

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

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