Что такое функция активации?

Одна из важнейших частей нейронной сети

Функция активации определяет выход нейрона / узла при заданном входе или наборе входных данных (выход нескольких нейронов). Это имитация стимуляции биологического нейрона.

Выход функции активации на следующий уровень (в мелкой нейронной сети: входной уровень и выходной уровень, а в глубокой сети - на следующий скрытый уровень) называется прямым распространением (распространением информации). Это считается нелинейным преобразованием нейронной сети.

Блокнот со всем кодом доступен здесь: GitHub

Вот список часто используемых функций активации:

  • Двоичный
  • Линейный
  • сигмовидная
  • Тань
  • ReLU
  • Утечка ReLU (LReLU)
  • Параметрическое ReLU (PReLU)
  • Экспоненциальная линейная единица (eLU)
  • ReLU-6
  • Softplus
  • Softsign
  • Софтмакс
  • Swish

Двоичный

Бинарная функция активации самая простая. Он основан на двоичном классификаторе, на выходе будет 0, если значения отрицательные, иначе 1. Считайте эту функцию активации порогом в двоичной классификации.

Код для бинарной функции активации:

def binary_active_function(x):
    return 0 if x < 0 else 1

Что дает эта функция?

for i in [-5, -3, -1, 0, 2, 5]:
    print(binary_active_function(i))
output:
    0
    0
    0
    1
    1
    1

Или визуально:

Pro:

  • Бинарная классификация

Минусы:

  • Не работает в многоуровневой классификации.
  • Производная для вычисления градиента всегда равна 0, поэтому невозможно обновить веса.

Линейная функция активации

Следующим шагом после двоичной функции является использование линейной функции вместо шага. Выход пропорционален входу.

Соответствующий код:

def linear_active_function(a, x):
    return a*x

Мы можем вычислить его для разных значений «:

$ x = numpy.linspace(-10, 10, 5000)
$ y_1 = [linear_active_function(1, i) for i in x] # a = 1
$ y_2 = [linear_active_function(2, i) for i in x] # a = 2
$ y_1
> [-10.0, -9.9, -9.8, -9.7, ..., 9.7, 9.8, 9.9, 10.0]

Если мы построим график результатов для a = 1, 2, 4 и 10:

Плюсы:

  • Бинарная и мультиклассовая классификация
  • Легко интерпретируемый

Минусы:

  • Производная соответствует «a», поэтому обновление весов и смещений во время обратного воспроизведения будет постоянным.
  • Неэффективно, если градиент всегда один и тот же.

Сигмовидная

Сигмоид - наиболее часто используемая функция активации с ReLU и tanh. Это нелинейная функция активации, также называемая логистической функцией. Выходные данные этой функции активации варьируются от 0 до 1. Все выходные сигналы нейронов будут положительными.

Соответствующий код выглядит следующим образом:

def sigmoid_active_function(x):
    return 1./(1+numpy.exp(-x))

Быстрое вычисление:

$ x = numpy.linspace(-10, 10, 5000)
$ y = [sigmoid_active_function(i) for i in x] 
$ y
> [4.5397868702434395e-05, 4.5854103946941324e-05, ... , 0.9999532196250409, 0.9999536850759906, 0.9999541458960531]

Если мы построим график результатов:

Минусы:

  • Проблема этой функции в том, что выходной сигнал каждого нейрона может насыщаться. Значения больше 1 имеют форму 1, а значения меньше 0 имеют форму 0.
  • Лучшая чувствительность для сигмовидной функции - около центральной точки (0, 0,5).
  • Большая проблема возникает во время насыщения, алгоритм не может обучиться во время этого положения (это источник проблемы исчезающего градиента, соответствующей отсутствию направления в градиенте).

Тань

Касательная гиперболическая функция (tanh) похожа на сигмоидную функцию в том смысле, что они похожи по форме. Tanh симметричен по 0, а значения находятся в диапазоне от -1 до 1. Как и сигмоид, они очень чувствительны в центральной точке (0, 0), но они насыщаются для очень большого числа (положительного и отрицательного). Эта симметрия делает их лучше, чем сигмовидная функция.

Соответствующий код для применения функции tanh:

def tanh_active_function(x):
    return 2*sigmoid_active_function(2*x)-1

Вычислите значения y:

$ x = numpy.linspace(-10, 10, 5000)
$ y = [tanh_active_function(i) for i in x] 
$ y
> [-0.9999999958776927, -0.9999999957944167, ... , 0.9999999956227836, 0.9999999957094583, 0.9999999957944166]

И соответствующий результат:

Плюсы:

  • Диапазон от -1 до 1
  • Градиент сильнее сигмовидной (производные круче)

Минусы:

  • Как и сигмоид, у tanh есть проблема с исчезающим градиентом.
  • Насыщенность

ReLU

Ректифицированная линейная единица была разработана, чтобы избежать насыщения большими положительными числами. Нелинейность позволяет сохранять и изучать закономерности внутри данных, а линейная часть (›0 - также называемая кусочно-линейной функцией) делает их легко интерпретируемыми.

В приведенной ниже функции показано, как реализовать функцию ReLU:

def relu_active_function(x):
    return numpy.array([0, x]).max()

Вычисление y:

$ x = numpy.linspace(-10, 10, 5000)
$ y = [relu_active_function(i) for i in x] 
$ y
> [0.0, 0.0, ... , 9.97, 9.98, 9.99]

Результаты:

Плюсы:

  • Легко внедрить и очень быстро
  • Истинное значение 0
  • Оптимизация проста, когда функция активации линейна
  • Наиболее часто используется в экосистеме нейронных сетей

Минусы:

  • Функция не может быть дифференцируемой, когда x = 0. Градиентный спуск не может быть вычислен для этой точки, но на практике это не влияет. Линейная часть соответствует наклону со значением 1, а отрицательная часть равна нулю.
  • «Умирающая проблема ReLU»: соответствует неактивной части нейронов, если выход равен 0. Нет градиента, когда нейроны неактивны, поэтому, если большая часть нейронов не активирована, это может привести к плохой работе модели.
  • Не подходит для алгоритма класса RNN (RNN, LSTM, GRU)

Дырявый ReLU

Эта функция активации является модификацией функции активации ReLU, чтобы избежать «умирающей проблемы». Функция возвращает линейный наклон, где a = 0,01, что позволяет поддерживать нейроны в активном состоянии с градиентным потоком.

См. Код ниже:

def leaky_relu_active_function(x):
    return 0.01*x if x < 0 else x

Вычислите ось Y, чтобы отобразить результаты:

$ x = numpy.linspace(-10, 10, 5000)
$ y = [leaky_relu_active_function(i) for i in x] 
$ y
> [-0.1, -0.0999, ... , 9.97, 9.98, 9.99]

Постройте результаты:

Плюсы:

  • Исправьте «проблему умирающего ReLU»
  • Тот же состав функции активации ReLU для части y = x

Параметрическое ReLU

После Leaky ReLU создается еще одна функция активации, чтобы избежать «умирающей проблемы ReLU», параметрического или параметризованного ReLU. Коэффициент a не является фиксированным на уровне 0,01 (Leaky ReLU), но его можно оценить. Это обобщение ReLU, алгоритм изучает параметр выпрямителя.

Код:

def parametric_relu_active_function(a, x):
    return a*x if x < 0 else x

Вычислите результаты для разных значений a:

$ x   = numpy.linspace(-10, 10, 5000)
$ y_1 = [parametric_relu_active_function(0.25, i) for i in x] 
$ y_2 = [parametric_relu_active_function(0.5, i) for i in x]
$ y_3 = [parametric_relu_active_function(0.75, i) for i in x]
$ y_4 = [parametric_relu_active_function(1, i) for i in x]
$ y_1
> [-2.5, -2.4975, ... , 9.97, 9.98, 9.99]

Постройте результаты для a = 0,25, 0,5, 0,75, 1:

Если a = 0, параметрическое ReLU эквивалентно функции активации ReLU. Если a = 0,01, параметрическое ReLU соответствует Leaky ReLU.

Плюсы:

  • Обобщить функцию активации ReLU
  • Избегайте «умирающей проблемы ReLU»
  • Параметр «a» изучается нейронной сетью.

Экспоненциальная линейная единица (eLU)

eLU - это еще один вариант функции ReLU. Отрицательная часть функции обрабатывается экспоненциальной функцией с медленным сглаживанием.

Соответствующая функция:

def elu_active_function(a, x):
    return a*(numpy.exp(x)-1) if x < 0 else x

Вычисление y:

$ x   = numpy.linspace(-10, 10, 5000)
$ y_1 = [elu_active_function(0.1, i) for i in x] 
$ y_2 = [elu_active_function(1, i) for i in x]
$ y_3 = [elu_active_function(2, i) for i in x]
$ y_4 = [elu_active_function(5, i) for i in x]
$ y_1
> [-0.09999546000702375, -0.09999541437933579, ... , 9.97, 9.98, 9.99]

Постройте результаты для a = 0,1, 1, 2, 4:

Плюсы:

  • ELU медленно сглаживается, пока его выход не станет равным -α, тогда как RELU резко сглаживается.
  • ELU - сильная альтернатива ReLU.
  • В отличие от ReLU, ELU может давать отрицательные выходы.

Минусы:

  • При x ›0 он может взорвать активацию с выходным диапазоном [0, inf].

ReLU-6

Другой вариант функции ReLU - это ReLU-6, 6 - произвольный параметр, фиксируемый вручную. Преимущество состоит в том, чтобы преобразовать вывод для большого положительного числа в значение 6.

Соответствующий код:

def relu_6_active_function(x):
    return numpy.array([0, x]).max() if x<6 else 6

Вычисление y:

$ y = [relu_6_active_function(i) for i in x]

Постройте результаты:

Softplus

Функция активации softplus является альтернативой сигмовидной и tanh-функциям. У этой функции есть пределы (верхний, нижний), но softplus находится в диапазоне (0, + inf).

Соответствующий код:

def softplus_active_function(x):
    return math.log(1+numpy.exp(x))

Вычисление y:

$ y = [softplus_active_function(i) for i in x]

Постройте результаты:

Софтсайн

Эта функция активации является разновидностью tanh, но на практике не очень часто используется. Функции tanh и softsign тесно связаны, tanh сходится экспоненциально, тогда как softtsign сходится полиномиально.

Соответствующий код:

def softsign_active_function(x):
    return x / (1 + abs(x) )
$ y = [softsign_active_function(i) for i in x]

Постройте результаты:

Софтмакс

Функция активации softmax отличается от других, потому что она вычисляет распределение вероятностей. Сумма на выходе равна 1.

Соответствующий код:

def softmax_active_function(x):
    return numpy.exp(x)/numpy.sum(numpy.exp(x))

Вычислить результат отличается, потому что это распределение вероятностей, учитывающее сумму экспонент, функции нужны все точки x для вычисления результата y.

$ x = [0.8, 1.2, 2.4, 4.6]
$ y = softmax_active_function(x)
$ y
> [0.01917691, 0.02860859, 0.09498386, 0.85723064]
$ numpy.sum(y)
> 1.0

Свист

Swish - это новая функция активации, опубликованная Google в 2017 году, она улучшает производительность ReLU на более глубоких моделях. Эта функция является разновидностью сигмоидной функции, потому что она может быть выражена следующим образом: x * sigmoid (x).

Swish обладает свойствами односторонней ограниченности в нуле, гладкости и немонотонности, которые могут играть роль в наблюдаемой эффективности Swish и аналогичных функций активации.
SWISH: ФУНКЦИЯ САМОЗАБРАННОЙ АКТИВАЦИИ, Prajit Рамачандран ∗, Баррет Зоф, Куок В. Ле, 2017

Соответствующие коды:

def swish_active_function(x):
    return x/(1+numpy.exp(-x))

Or:

def swish_active_function(x):
    return x*sigmoid_active_function(x)

Вычислить значения:

$ x = numpy.linspace(-10, 10, 5000)
$ y = [swish_active_function(i) for i in x]
$ y
> [-0.0004539786870243439, -0.0004967044303692657, ..., 9.699405586525717, 9.799456604457717, 9.89950329556963]

Постройте результаты:

Плюсы:

  • Отличие по каждому пункту по сравнению с ReLU

Вывод

Здесь представлены некоторые функции активации (наиболее популярные) с их кодом и представлением. Надеюсь, что эта визуализация позволит каждому понять, что делают нейроны, и определить, какая функция лучше подходит для задачи, над которой они работают.

Последний график соответствует стеку функций активации на одном графике.

использованная литература