Исторически одна из первых функций активации. Рассматривалась в том числе и как гладкая аппроксимация порогового правила, эмулирующая активацию естественного нейрона.
На практике редко используется внутри сетей, чаще всего в случаях, когда внутри модели решается задача бинарной классификации.
Проблемы:
- На концах функции (значения рядом с 0 и 1) производная практически равна 0, что приводит к затуханию градиентов.
- область значений смещена относительно нуля;
- exp вычислительно дорогая операция (ReLU быстрее в 4-6 раз)
class Sigmoid(Module):
def forward(self, input):
self.output = self.__class__._sigmoid(input)
return self.output
def backward(self, input, grad_output):
sigma = self.output
grad_input = np.multiply(grad_output, sigma*(1 - sigma))
return grad_input
@staticmethod
def _sigmoid(x):
return 1/(1 + np.exp(-x))
Tanh решает проблему несимметричности Sigmoid и также может быть записан через неё
Плюсы:
- Имеет симметричную область значений относительно нуля (в отличие от сигмоиды)
- Имеет ограниченную область (-1, 1)
Минусы:
- Проблема затухания градиентов на концах функции (близи значений -1 и 1), там производная почти равна 0
- требуется вычисление exp, что вычислительно дорого
Из основного тождества
class Tanh(Module):
def forward(self, input):
self.output = np.tanh(input)
return self.output
def backward(self, input, grad_output):
th = self.output
grad_input = np.multiply(grad_output, (1 - th*th))
return grad_input
ReLU представляет собой простую кусочно-линейную функцию. Одна из наиболее популярных функций активации. В нуле производная доопределяется нулевым значением.
Плюсы: + сходится быстро (относительно sigmoid из-за отсутсвие проблемы с затуханием градиентов) + вычислительная простота активции и производной (Прирост в скорости относительно сигмойды в 4-6 раз) + не saturated nonlinear
Минусы: - для отрицательных значений производная равна нулю, что может привести к затуханию градиента; - область значений является смещённой относительно нуля.
Пусть
class ReLU(Module):
"""Rectified linear unit. Activation function."""
def forward(self, input):
self.output = np.maximum(input, 0)
return self.output
def backward(self, input, grad_output):
grad_input = np.multiply(grad_output, input > 0)
return grad_input
Модификация ReLU устраняющая проблему смерти градиентов при
Пусть
class LeakyReLU(Module):
def __init__(self, slope=0.01):
super().__init__()
self.slope = slope
def forward(self, input):
self.output = (input > 0)*input + (input <= 0)*self.slope*input
return self.output
def backward(self, input, grad_output):
grad_input = np.multiply(
grad_output, (input > 0) + (input <= 0)*self.slope
)
return grad_input
Softmax также известна, как softargmax или normalized exponential function. Softmax преобразует вектор из
Сумма элементов выходного вектор равна 1. Softmax является аппроксимацией функции argmax.
Если мы хотим продифференциировать
для всех
Пусть
class Softmax(Module):
def forward(self, input):
self.output = self.softmax = self._softmax(input)
return self.output
def backward(self, input, grad_output):
p = self.softmax
grad_input = p * ( grad_output - (grad_output * p).sum(axis=1)[:, None] )
return grad_input
def _softmax(self, x):
x = np.subtract(x, x.max(axis=1, keepdims=True))
e_m = np.exp(x)
sum_e = np.repeat(np.sum(e_m, axis=1), x.shape[-1]).reshape(*e_m.shape)
return e_m/sum_e