ReLU в обратном проходе
Почему через одни нейроны градиент проходит дальше, а через другие — нет
ReLU как ворота
Если во время forward значение было положительным, ReLU пропускает градиент назад. Если отрицательным — блокирует его.
Функция ReLU уже знакома:
\[ \operatorname{ReLU}(z)=\max(0,z). \]
Во время forward она работает очень просто:
если \(z>0\), то на выходе остаётся само значение \(z\); если \(z<0\), на выходе получается 0.
Локальная производная ReLU
Посмотрим на две части графика отдельно.
При \(z>0\) ReLU совпадает с прямой
\[ a=z. \]
Её наклон равен 1, поэтому:
\[ \frac{\partial a}{\partial z}=1. \]
При \(z<0\) выход ReLU постоянно равен нулю:
\[ a=0. \]
Наклон горизонтальной части равен 0:
\[ \frac{\partial a}{\partial z}=0. \]
Поэтому производную ReLU можно записать так:
\[ \frac{\partial \operatorname{ReLU}(z)}{\partial z} = \begin{cases} 0, & z<0,\\ 1, & z>0. \end{cases} \]
В точке \(z=0\) обычная производная не определена. В программной реализации нужно выбрать соглашение; обычно в этой точке используют 0.
Что происходит во время backward
Пусть ReLU находится внутри вычислительного графа:
\[ z \rightarrow \operatorname{ReLU} \rightarrow a \rightarrow \dots \rightarrow L. \]
Во время backward к выходу ReLU уже приходит некоторый градиент:
\[ \frac{\partial L}{\partial a}. \]
Нужно передать его дальше — к \(z\).
По цепному правилу:
\[ \frac{\partial L}{\partial z} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z}. \]
И здесь всё определяется тем, какое значение \(z\) было получено во время forward.
Если во время forward было \(z>0\)
Локальная производная ReLU:
\[ \frac{\partial a}{\partial z}=1. \]
Поэтому:
\[ \frac{\partial L}{\partial z} = \frac{\partial L}{\partial a}\cdot1 = \frac{\partial L}{\partial a}. \]
Градиент проходит назад без изменения.
Если во время forward было \(z<0\)
Локальная производная ReLU:
\[ \frac{\partial a}{\partial z}=0. \]
Поэтому:
\[ \frac{\partial L}{\partial z} = \frac{\partial L}{\partial a}\cdot0 = 0. \]
Градиент дальше не проходит.
Числовой пример
Пусть к ReLU во время backward пришёл один и тот же градиент:
\[ \frac{\partial L}{\partial a}=5. \]
Рассмотрим два случая.
Во время forward: \(z=2.4\)
Значение положительное, поэтому:
\[ \frac{\partial a}{\partial z}=1. \]
Получаем:
\[ \frac{\partial L}{\partial z} = 5\cdot1 = 5. \]
Во время forward: \(z=-2.4\)
Значение отрицательное, поэтому:
\[ \frac{\partial a}{\partial z}=0. \]
Получаем:
\[ \frac{\partial L}{\partial z} = 5\cdot0 = 0. \]
Обрати внимание: к ReLU в обоих случаях пришёл один и тот же градиент — \(5\). Но назад получились разные значения.
Причина не в пришедшем градиенте, а в результате предыдущего forward: в одном случае \(z>0\), а в другом \(z<0\).
Зачем backward нужен результат forward
Чтобы выполнить backward через ReLU, недостаточно знать только пришедший градиент. Нужно ещё знать, каким было значение \(z\) во время прямого прохода.
Если \(z\) было положительным — градиент нужно пропустить.
Если \(z\) было отрицательным — градиент нужно обнулить.
Поэтому некоторые значения, вычисленные во время forward, приходится сохранять: они понадобятся позже при обратном проходе.
ReLU в backward:
если \(z>0\) — пропускаем пришедший градиент;
если \(z\leq0\) — передаём 0.