Лекция 05

Обратное распространение ошибки

Обратный поток градиентов по сети
Вперёд идёт предсказание, назад — сигнал «насколько каждый вес виноват в ошибке».

Нейросеть — композиция функций. Производную композиции даёт цепное правило. Для скаляров

$$\frac{d}{dx}f(g(x)) = f'(g(x))\,g'(x)$$

Для векторов появляется якобиан. Если \(\mathbf{u}=g(\mathbf{x})\), \(\ell=f(\mathbf{u})\), то

$$\nabla_{\mathbf{x}}\ell = \left(\frac{\partial\mathbf{u}}{\partial\mathbf{x}}\right)^\top \nabla_{\mathbf{u}}\ell$$

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

Дельта слоя

Обозначим \(\delta^{(\ell)}=\nabla_{\mathbf{z}^{(\ell)}}\ell\). Тогда для MLP:

$$\delta^{(L)} = \nabla_{\mathbf{a}^{(L)}}\ell \,\odot\, \sigma'( \mathbf{z}^{(L)} )$$
$$\delta^{(\ell)} = \left( (W^{(\ell+1)})^\top \delta^{(\ell+1)} \right) \odot \sigma'(\mathbf{z}^{(\ell)})$$

Градиенты параметров собираются из дельты и активации предыдущего слоя:

$$\nabla_{W^{(\ell)}}\ell = \delta^{(\ell)} (\mathbf{a}^{(\ell-1)})^\top, \qquad \nabla_{\mathbf{b}^{(\ell)}}\ell = \delta^{(\ell)}$$

Почему это дёшево

Наивный подсчёт каждой частной производной по отдельности стоил бы примерно столько же, сколько \(|\theta|\) прямых проходов. Обратный режим автоматического дифференцирования считает весь градиент за время того же порядка, что и один прямой ход. Константа обычно от 2 до 5.

Исчезающие и взрывающиеся градиенты

Повторное умножение якобианов даёт произведение

$$\frac{\partial \ell}{\partial\mathbf{a}^{(1)}} = \frac{\partial \ell}{\partial\mathbf{a}^{(L)}} \prod_{\ell=2}^{L} \frac{\partial\mathbf{a}^{(\ell)}}{\partial\mathbf{a}^{(\ell-1)}}$$

Если спектральный радиус множителей меньше единицы, сигнал затухает; если больше — взрывается. Отсюда ReLU, residual-связи и нормализация.

Residual-блок

ResNet добавляет обходной путь:

$$\mathbf{a}^{(\ell+1)} = \mathbf{a}^{(\ell)} + \mathcal{F}(\mathbf{a}^{(\ell)};\theta_\ell)$$

Градиент по входу содержит единицу плюс обычный путь через \(\mathcal{F}\). Единица не даёт сигналу полностью исчезнуть.

Фреймворки вроде PyTorch не просят писать backprop вручную: они строят граф операций на прямом ходе и применяют цепное правило автоматически. Понимать формулы всё равно полезно — иначе трудно искать, почему градиент ноль.