Сеть доставки: backward
Проходим всю сеть в обратном направлении и получаем градиенты её параметров
Контроль формы
Градиент параметра имеет ту же форму, что и сам параметр.
Это один из самых простых способов заметить ошибку в вычислениях.
Во время forward мы получили:
\[
x=[4,2,6],
\]
\[
z_1=[2,3.5],
\qquad
a_1=[2,3.5],
\]
\[
\hat y=8.5,
\qquad
y=20,
\qquad
L=132.25.
\]
Теперь идём по той же сети в обратном направлении:
\[
L
\longrightarrow
\hat y
\longrightarrow
a_1
\longrightarrow
z_1
\longrightarrow
W_1.
\]
На каждом участке используем уже знакомое правило:
пришедший градиент умножаем на локальную производную.
Шаг 1. От loss к прогнозу
Функция потерь:
\[
L=(\hat y-y)^2.
\]
Нас интересует, как изменение прогноза влияет на loss:
\[
\frac{\partial L}{\partial \hat y}
=
2(\hat y-y).
\]
Подставляем значения:
\[
\frac{\partial L}{\partial \hat y}
=
2(8.5-20)
=
2\cdot(-11.5)
=
-23.
\]
Получили первый градиент обратного прохода:
\[
\frac{\partial L}{\partial \hat y}=-23.
\]
Что означает знак минус?
Прогноз \(8.5\) меньше правильного значения \(20\).
Если немного увеличить прогноз, ошибка уменьшится.
Поэтому производная отрицательна.
Шаг 2. Градиенты весов выходного слоя
Выходной слой вычислял:
\[
\hat y
=
2a_{1,1}
-
a_{1,2}
+
8.
\]
Его параметры:
\[
W_2=
\begin{bmatrix}
2\\
-1
\end{bmatrix},
\qquad
b_2=8.
\]
Во время forward на вход выходного слоя пришло:
\[
a_1=[2,3.5].
\]
Рассмотрим первый вес \(W_{2,1}\).
Если изменить только этот вес, прогноз изменяется через произведение
\[
a_{1,1}W_{2,1}.
\]
Поэтому локальная производная:
\[
\frac{\partial \hat y}{\partial W_{2,1}}
=
a_{1,1}
=
2.
\]
Передаём пришедший градиент:
\[
\frac{\partial L}{\partial W_{2,1}}
=
\frac{\partial L}{\partial \hat y}
\cdot
\frac{\partial \hat y}{\partial W_{2,1}}
=
-23\cdot2
=
-46.
\]
Для второго веса:
\[
\frac{\partial \hat y}{\partial W_{2,2}}
=
a_{1,2}
=
3.5,
\]
поэтому:
\[
\frac{\partial L}{\partial W_{2,2}}
=
-23\cdot3.5
=
-80.5.
\]
Собираем оба значения:
\[
\frac{\partial L}{\partial W_2}
=
\begin{bmatrix}
-46\\
-80.5
\end{bmatrix}.
\]
Смещение \(b_2\) прибавляется к прогнозу напрямую:
\[
\frac{\partial \hat y}{\partial b_2}=1.
\]
Значит:
\[
\frac{\partial L}{\partial b_2}
=
-23\cdot1
=
-23.
\]
Параметры
\[
W_2:
(2\times1)
\]
\[
b_2:
1
\]
Их градиенты
\[
\frac{\partial L}{\partial W_2}:
(2\times1)
\]
\[
\frac{\partial L}{\partial b_2}:
1
\]
Шаг 3. Передаём градиент скрытому слою
Градиенты параметров \(W_2\) мы уже получили.
Но backward должен идти дальше — к первому слою.
Для этого нужно узнать, как loss зависит от двух скрытых активаций:
\[
a_{1,1},
\qquad
a_{1,2}.
\]
Выходной слой:
\[
\hat y
=
2a_{1,1}
-
a_{1,2}
+
8.
\]
Поэтому:
\[
\frac{\partial \hat y}{\partial a_{1,1}}
=
2,
\qquad
\frac{\partial \hat y}{\partial a_{1,2}}
=
-1.
\]
Передаём назад градиент \(-23\).
Первый скрытый нейрон
\[
\frac{\partial L}{\partial a_{1,1}}
=
-23\cdot2
=
-46.
\]
Второй скрытый нейрон
\[
\frac{\partial L}{\partial a_{1,2}}
=
-23\cdot(-1)
=
23.
\]
Получаем вектор:
\[
\frac{\partial L}{\partial a_1}
=
[-46,23].
\]
Обрати внимание: здесь мы использовали веса \(W_2\).
Когда вычисляли градиент по весу, множителем был вход слоя.
Теперь вычисляем градиент по входу слоя, поэтому множителем становится вес.
Шаг 4. Проходим назад через ReLU
Во время forward было:
\[
z_1=[2,3.5].
\]
Оба значения положительны, поэтому для обоих нейронов:
\[
\operatorname{ReLU}'(z)=1.
\]
Следовательно:
\[
\frac{\partial L}{\partial z_1}
=
\frac{\partial L}{\partial a_1}
\odot
[1,1].
\]
Знак \(\odot\) означает поэлементное умножение.
Получаем:
\[
\frac{\partial L}{\partial z_1}
=
[-46,23].
\]
Почему значения не изменились?
Оба \(z\) были положительными.
Поэтому оба «ворота» ReLU открыты и умножают пришедший градиент на 1.
Если бы одно из значений \(z\) было отрицательным,
соответствующий компонент градиента здесь превратился бы в 0.
Шаг 5. Доходим до первого слоя
Теперь известен градиент по двум линейным выходам первого слоя:
\[
\frac{\partial L}{\partial z_1}
=
[-46,23].
\]
Напомним вход сети:
\[
x=[4,2,6].
\]
Каждый вход соединён с обоими скрытыми нейронами.
Поэтому для каждого входного признака получится два градиента весов.
Для первого признака \(x_1=4\):
\[
4\cdot[-46,23]
=
[-184,92].
\]
Это первая строка градиента \(W_1\).
Для второго признака \(x_2=2\):
\[
2\cdot[-46,23]
=
[-92,46].
\]
Для третьего признака \(x_3=6\):
\[
6\cdot[-46,23]
=
[-276,138].
\]
Собираем строки вместе:
\[
\frac{\partial L}{\partial W_1}
=
\begin{bmatrix}
-184 & 92\\
-92 & 46\\
-276 & 138
\end{bmatrix}.
\]
А что со смещениями первого слоя?
Для каждого скрытого нейрона смещение прибавлялось напрямую:
\[
z_{1,j}
=
\dots+b_{1,j}.
\]
Локальная производная по смещению равна 1.
Поэтому:
\[
\frac{\partial L}{\partial b_1}
=
[-46,23].
\]
Первый слой
\[
W_1:
(3\times2)
\]
\[
b_1:
(2)
\]
Градиенты первого слоя
\[
\frac{\partial L}{\partial W_1}:
(3\times2)
\]
\[
\frac{\partial L}{\partial b_1}:
(2)
\]
Backward завершён
Теперь известны градиенты всех обучаемых параметров сети:
\[
\frac{\partial L}{\partial W_2}
=
\begin{bmatrix}
-46\\
-80.5
\end{bmatrix},
\qquad
\frac{\partial L}{\partial b_2}
=
-23,
\]
\[
\frac{\partial L}{\partial W_1}
=
\begin{bmatrix}
-184 & 92\\
-92 & 46\\
-276 & 138
\end{bmatrix},
\qquad
\frac{\partial L}{\partial b_1}
=
[-46,23].
\]
На этом собственно backward закончен.
Ни один вес пока не изменился.
Теперь отдельный шаг градиентного спуска может использовать найденные значения.
Например, что произойдёт с одним весом
Возьмём первый вес первого слоя:
\[
w=0.5.
\]
Для него мы получили:
\[
\frac{\partial L}{\partial w}
=
-184.
\]
При скорости обучения
\[
\eta=0.001
\]
шаг градиентного спуска:
\[
w_{\text{new}}
=
w_{\text{old}}
-
\eta
\frac{\partial L}{\partial w}.
\]
Подставляем:
\[
w_{\text{new}}
=
0.5
-
0.001\cdot(-184)
=
0.684.
\]
Отрицательный градиент привёл к увеличению веса.
Именно так найденные backward градиенты превращаются в реальное обучение сети.
Весь backward:
\[
L
\rightarrow
\hat y
\rightarrow
a_1
\rightarrow
z_1
\rightarrow
W_1,b_1.
\]
По пути мы также получили градиенты \(W_2\) и \(b_2\).
Backward вычисляет градиенты.
Step использует их для изменения параметров.