Как ответить
Суть: Переход с tanh/sigmoid на ReLU решил проблему затухающих градиентов (vanishing gradients) и ускорил обучение глубоких сетей. Tanh давал градиенты, близкие к нулю при больших и малых значениях, что тормозило сходимость. ReLU не насыщается на положительном участке, что позволяет градиентам свободно распространяться, а также вносит разреженность и дешевле вычисляется.
Подробнее: До ReLU стандартными функциями активации были сигмоида и гиперболический тангенс. Их производные принимают значения от 0 до 0,25 (tanh) и до 0,25 (sigmoid). При этом на краях аргумента производная практически нулевая. В глубоких сетях последовательное перемножение этих малых чисел (правило цепочки) приводило к экспоненциальному затуханию градиентов — первые слои практически не обучались.
ReLU (Rectified Linear Unit) — f(x) = max(0, x) — решает проблему кардинально:
- Градиент 1 для положительных x — не уменьшается при обратном распространении для активных нейронов.
- Разреженность — часть нейронов выключается (выход ноль), что экономит вычислительные ресурсы и уменьшает переобучение.
- Простота вычисления — всего одно сравнение, без экспонент.
Но у ReLU есть недостатки:
- Умирающие нейроны — если нейрон попадает в область
x < 0для всех данных, его градиент равен нулю, и он никогда не восстанавливается. - Неограниченный выход — может взрывать активации.
Для борьбы с умиранием нейронов появились модификации: Leaky ReLU (max(0.01x, x)), PReLU (с обучаемым коэффициентом), ELU (с гладким отрицательным участком). Однако стандартный ReLU остаётся самым популярным выбором «по умолчанию» для скрытых слоёв в feedforward и свёрточных сетях.
# Пример сравнения производных в torch
import torch.nn as nn
import torch
x = torch.tensor([-10.0, -1.0, 0.0, 1.0, 10.0])
tanh = nn.Tanh()
relu = nn.ReLU()
# Производная tanh убывает на краях
dx_tanh = 1 - tanh(x)**2
print('tanh derivative:', dx_tanh)
# Производная ReLU – константа 1 для x>0, 0 для x<=0
dx_relu = torch.where(x > 0, 1.0, 0.0)
print('ReLU derivative:', dx_relu)