Как изменяются веса при обратном распространении в нейронных сетях - PullRequest
0 голосов
/ 13 мая 2019

Итак, я знаю, что обратное распространение использует градиенты и передает их обратно через нейронную сеть для обновления весов.Но как именно обновляются веса для слоев в середине.Используют ли выходные слои те же градиенты, что и выходные слои, или они имеют разные градиенты для обновления весов?

1 Ответ

1 голос
/ 23 мая 2019

На каждом уровне ваша нейронная сеть снова и снова производит следующие промежуточные вычисления:

z[l] = a[l] * w[l] + b[l]
a[l+1] = f[l](z[l])

, где [0] - ваш исходный вход в нейронную сеть.z [l] является взвешенной суммой предыдущей активации a [l] (помните, что a [0] является входом), а затем веса для l-го слоя w [l] добавляет b [l], что является смещениемвектор.Активация для текущего слоя затем вычисляется путем применения функции активации (f [l] (x) - помните, что вы можете иметь разные функции активации для каждого слоя) на ранее вычисленном z.Это ваш прямой пропуск.Вы повторяете вышеописанные шаги снова и снова для всех слоев.

Для распространения ошибок в обратном направлении необходимо дифференцировать функцию стоимости по каждой из весовых матриц, начиная с последней по направлению кпервый:

DW [л], DW [л-1], ..., DW [1], DW [0]

Давайте возьмем игрушкупример.У вас есть нейронная сеть с одним скрытым слоем и выходным слоем, таким образом, у вас есть [0] для ваших входов, z [0] в качестве взвешенных значений на скрытом слое, a [1] в качестве активации на скрытом слое, z [1] как взвешенные некоторые на выходном слое, a [2] как предположение сети для входа.У вас также есть w [0] для весов на скрытом слое и w [1] для весов для выходного слоя.Наконец, конечно, есть b [0] для скрытого и b [1] для выходных смещений.

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

  • dE / dw [1]

  • dE / dw [0]

Первый - это веса на выходном слое, а следующий -веса на скрытом слое.

dE/dw[0] := dE/da[2] * da[2]/dz[1] * dz[1]/dw[1]

If, E := np.mean(np.sum(.5 * (a[2] - Y)**2, axis=1), axis=0)
then:
dE/da[2] = (a[2] - Y)

For da[2]/dz[1], remember that a[l+1] = f[l](z[1]):
da[2]/dz[1] = df[l](z[1])

Finally:
dz[1]/dw[1] = a[1]

dE/dw[0] = (a[2] - Y) * df[l](z[1]) @ a[1]

Где, * - поэлементное умножение, а @ - стандартное хорошо известное матричное умножение.Теперь существуют разные подходы для инициализации весовых матриц и организации входной матрицы для мини-спуска градиентного спуска, так что выше все еще требуется некоторая работа.Обычно вам нужно переставить [1] и / или умножить [1] .T на остальные.Но расчет такой.Теперь для скрытого слоя все просто продолжается:

dE/dw[0] := dE/da[2] * da[2]/dz[1] * dz[1]/da[1] * da[1]/dz[0] * dz[0]/dw[0]

Where dE/da[2] * da[2]/dz[1] is common and is called d[1] a.k.a the delta for the output layer.

dz[1]/da[1] = w[1]
da[1]/dz[0] = df[0](z[0])
dz[0]/dw[0] = a[0]

dE/dw[0] = d[1] @ w[1] * df[0](z[0]) * a[0]

Еще раз, возможно, потребуется транспонировать w [1] и a [0], и это зависит от того, как вы проектируете свою сеть, но расчеттам.

Короче говоря, это просто применение цепного правила снова и снова.Учитывая слой [i], у вас будет некоторая дельта d [i + 1] от следующего слоя, тогда вам нужно вычислить dw [i] для текущего слоя и d [i] для предыдущего [i-1]-й слой:

d[i] = d[i+1] @ w[i+1] * df[i](z[i])
dw[i] = d[i] @ a[i]

И повторите это для всех слоев вашей сети от последнего к первому.Я надеюсь, что это проясняется.

...