Статья Автор: Деникина Н.В., Деникин А.В.

Почему считаем с конца

Почему считаем с конца

От функции потерь назад по тому же графу, по которому шёл forward

Не путать
Backward вычисляет градиенты. Он не меняет веса: изменение параметров делает отдельный шаг оптимизатора.

Нас интересует итоговая величина \(L\), поэтому обратный проход удобно начинать именно с неё.

Самая первая производная очевидна:

\[ \frac{\partial L}{\partial L}=1. \]

Это означает, что изменение \(L\) по отношению к самому себе передаётся с коэффициентом 1.

Теперь двигаемся на один шаг назад.

Последняя операция была:

\[ L=b^2. \]

При \(b=10\):

\[ \frac{\partial L}{\partial b} = 2b = 20. \]

Теперь мы знаем, насколько функция потерь чувствительна к небольшому изменению \(b\).

Ещё один шаг назад

Предыдущая операция:

\[ b=a+4. \]

Её локальная производная:

\[ \frac{\partial b}{\partial a}=1. \]

К этой операции уже пришёл градиент:

\[ \frac{\partial L}{\partial b}=20. \]

Чтобы передать его дальше к \(a\), используем цепное правило:

\[ \frac{\partial L}{\partial a} = \frac{\partial L}{\partial b} \cdot \frac{\partial b}{\partial a}. \]

Подставляем:

\[ \frac{\partial L}{\partial a} = 20\cdot1 = 20. \]

На каждом шаге backward: пришедший градиент умножаем на локальную производную текущей операции.
Доходим до x

Осталась первая операция:

\[ a=3x. \]

Её локальная производная:

\[ \frac{\partial a}{\partial x}=3. \]

Пришедший градиент:

\[ \frac{\partial L}{\partial a}=20. \]

Поэтому:

\[ \frac{\partial L}{\partial x} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial x} = 20\cdot3 = 60. \]

Что нам даёт этот результат

Мы получили:

\[ \frac{\partial L}{\partial x}=60. \]

Это означает: около текущей точки небольшое увеличение \(x\) увеличивает функцию потерь примерно в 60 раз сильнее.

Но \(x\) здесь — входное значение. В реальной нейронной сети входные данные обычно не меняют во время обучения.

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

\[ \frac{\partial L}{\partial w_1}, \qquad \frac{\partial L}{\partial w_2}, \qquad \dots \]

Backward тем же способом проходит назад по графу и доходит до каждого обучаемого параметра.

Зачем нужен backward?

Он доставляет до каждого веса число

\[ \frac{\partial L}{\partial w}, \]

которое показывает, как изменение этого веса повлияет на функцию потерь.

Именно это число затем использует градиентный спуск.

Например, если для некоторого веса получилось:

\[ \frac{\partial L}{\partial w}=60, \]

а скорость обучения равна:

\[ \eta=0.01, \]

то шаг градиентного спуска будет:

\[ w_{\text{new}} = w_{\text{old}} - 0.01\cdot60. \]

То есть вес уменьшится на \(0.6\).

Если бы градиент был отрицательным, вес изменился бы в противоположную сторону.

Forward и backward идут по одному графу

Во время прямого прохода мы двигались слева направо:

\[ x \rightarrow a \rightarrow b \rightarrow L. \]

Считали значения:

\[ 2 \rightarrow 6 \rightarrow 10 \rightarrow 100. \]

Во время backward идём по тому же пути в обратном направлении:

\[ L \rightarrow b \rightarrow a \rightarrow x. \]

И считаем уже не значения, а градиенты:

\[ 1 \rightarrow 20 \rightarrow 20 \rightarrow 60. \]

Обратное распространение, или backpropagation, — способ вычислять градиенты функции потерь по промежуточным значениям и параметрам, проходя по вычислительному графу от результата к его входам.

Backward не меняет веса

Это важно отделять от градиентного спуска.

Backward отвечает на вопрос:

каков градиент каждого параметра?

После backward мы получаем значения вида:

\[ \frac{\partial L}{\partial w}. \]

И только после этого выполняется уже знакомый шаг градиентного спуска:

\[ w_{\text{new}} = w_{\text{old}} - \eta \frac{\partial L}{\partial w}. \]

Forward считает значения.
Backward считает градиенты.
Step изменяет параметры.

Проверь себя

Что делает backward?


Как градиент проходит назад

Forward уже посчитал значения. Теперь по тому же графу передаём градиент в обратном направлении.

forward → x 2 a 6 b 10 L 100 ×3 +4 квадрат ← backward ×20 ×1 ×3 grad 60 grad 20 grad 20 grad 1 Начинаем с L: grad = 1
Старт

Backward начинается с функции потерь.

∂L ∂L = 1

Это число начинаем передавать справа налево.

Печать