Функции активации: sigmoid, tanh, ReLU

Урок разбирает три главные функции активации и объясняет, почему без нелинейности сеть бесполезна.

Функция активации — это нелинейное преобразование взвешенной суммы; именно она даёт сети способность выражать сложные зависимости.

Зачем вообще нелинейность

Представим, что активации нет: каждый слой просто считает W·x + b. Тогда два слоя подряд — это W2·(W1·x + b1) + b2, что после раскрытия снова сводится к одному линейному преобразованию W·x + b. Сколько ни ставь линейных слоёв, получится один линейный слой. Нелинейная активация между слоями ломает это схлопывание — и сеть начинает выражать кривые границы (вспомните XOR).

Три рабочие лошадки

  • sigmoid: сжимает вход в (0, 1). Хороша для вероятностей на выходе. Минус — на больших по модулю входах почти плоская, градиент близок к нулю (это вредит обучению глубоких сетей).
  • tanh: сжимает в (-1, 1), центрирована в нуле. Часто учится лучше sigmoid в скрытых слоях, но страдает тем же затуханием градиента на краях.
  • ReLU (max(0, x)): пропускает положительные значения как есть, отрицательные обнуляет. Простая, быстрая, не насыщается для положительных входов — сегодня дефолт для скрытых слоёв глубоких сетей.

Считаем и сравниваем

import math

def sigmoid(x):
    return 1.0 / (1.0 + math.exp(-x))

def tanh(x):
    return math.tanh(x)

def relu(x):
    return x if x > 0 else 0.0

print("x      sigmoid   tanh     relu")
for x in [-2, -1, 0, 1, 2]:
    print(f"{x:>2}   {sigmoid(x):>7.3f}  {tanh(x):>7.3f}  {relu(x):>5.1f}")

Вывод:

x      sigmoid   tanh     relu
-2     0.119   -0.964    0.0
-1     0.269   -0.762    0.0
 0     0.500    0.000    0.0
 1     0.731    0.762    1.0
 2     0.881    0.964    2.0

Видно главное: sigmoid и tanh «прижимаются» к границам на краях (их выход почти не меняется при больших входах), а ReLU для отрицательных входов жёстко обнуляется, для положительных — линейна.

Какую выбрать

ФункцияДиапазонГде применять
ReLU[0, +∞)скрытые слои по умолчанию
sigmoid(0, 1)выход бинарной классификации
tanh(-1, 1)скрытые слои, рекуррентные сети

У ReLU есть проблема «мёртвых нейронов»: если вход постоянно отрицательный, нейрон всегда выдаёт 0 и перестаёт учиться. Поэтому придумали варианты вроде Leaky ReLU (max(0.01*x, x)), которые оставляют маленький наклон для отрицательной части.

При чём тут производная

Выбор активации напрямую влияет на обучение через её производную — ту самую, что backprop перемножает по слоям. У sigmoid производная не больше 0.25 и почти зануляется на краях, поэтому в глубокой сети сигнал ошибки быстро гаснет (мы посчитаем это в разделе про затухание градиента). У ReLU производная для положительных входов равна ровно 1 — она ничего не сжимает и пропускает градиент без потерь. Это и есть главная причина, по которой ReLU вытеснила sigmoid из скрытых слоёв: дело не столько в самих значениях активации, сколько в том, как ведёт себя её производная при обратном проходе.

Есть и современные «гладкие» активации — GELU и SiLU (swish), — которые используют в трансформерах. Они похожи на ReLU, но плавно сглажены около нуля, что иногда чуть улучшает обучение больших моделей. Для начала же достаточно правила: скрытые слои — ReLU, выход — sigmoid (бинарная задача) или softmax (много классов).

Итог

  • Без нелинейной активации стопка слоёв схлопывается в один линейный слой.
  • sigmoid и tanh насыщаются на краях; ReLU — нет (для положительных входов).
  • ReLU — стандарт для скрытых слоёв, sigmoid/softmax — для выхода.
Проверьте себя
1. Что случится, если убрать нелинейные активации из всех слоёв?
AСеть будет учиться быстрее
BВся сеть схлопнется в одно линейное преобразование
CСеть перестанет считаться вовсе
DГрадиенты станут точнее
2. Чем ReLU отличается от sigmoid?
AReLU всегда возвращает значения в (0,1)
BReLU обнуляет отрицательные входы и не насыщается на положительных
CReLU центрирована в нуле как tanh
DReLU нелинейна, а sigmoid линейна
3. Почему говорят о проблеме «мёртвых нейронов» у ReLU?
AReLU выдаёт слишком большие числа
BНейрон с постоянно отрицательным входом всегда выдаёт 0 и перестаёт учиться
CReLU делит на ноль
DReLU не имеет смещения
Поддержать проект