激活函数
如果没有激活函数引入非线性,多层神经网络就相当于单层神经网络,非线性激活函数可以使得神经网络逼近任意复杂的函数。
1. Sigmoid函数
1.1 Sigmoid函数解析式
Sigmoid函数:
f ( x ) = 1 1 + e − x f(x) = \frac {1} {1 + e^{-x}} f(x)=1+e−x1
Sigmoid函数一阶导数:
f ′ ( x ) = ( 1 1 + e − x ) ′ = − 1 ( 1 + e − x ) 2 ( 1 + e − x ) ′ = 1 1 + e − x e − x 1 + e − x = f ∗ ( 1 − f ) \begin{aligned} f'(x) &= (\frac{1}{1 + e^{-x}})'\\ &=- \frac{1}{{(1+e^{-x}})^2} (1+e^{-x})'\\ &=\frac{1}{1+e^{-x}} \frac{e^{-x}}{1+e^{-x}} \\ &=f*(1-f) \end{aligned} f′(x)=(1+e−x1)′=−(1+e−x)21(1+e−x)′=1+e−x11+e−xe−x=f∗(1−f)
1.2 Sigmoid函数代码实现以及图像展示
import numpy as np
class Sigmoid(object):
"""
Sigmoid 激活函数
"""
def __str__(self):
return 'Sigmoid'
def __call__(self, x):
"""
调用此类是,可直接执行函数
:param x: 输入序列
"""
return self.fn(x)
def fn(self, x):
"""
$$f(x) = \frac {1} {1 + e^{-x}}$$
"""
x = np.array(x)
return 1 / (1 + np.exp(-1 * x))
def grad(self, x):
"""
Sigmoid 一阶导数: f'(x) = f(x) * (1 - f(x))
"""
return self.fn(x) * (1 - self.fn(x))
def plot(fn):
# 画图
import matplotlib.pyplot as plt
x = np.linspace(-6, 6, 100)
fig, ax = plt.subplots()
ax.plot(x, fn(x), c='red', label=r"$f(x)$")
ax.plot(x, fn.grad(x), label=r"$\partial f(x) / \partial x$")
ax.set_title("{}".format(fn))
ax.grid()
ax.legend()
plt.show()
plot(fn=Sigmoid())
1.3 Sigmoid函数的分析
如上图所示,Sigmoid的函数输出值在0-1之间,可以表示概率值。
Sigmoid函数有如下几个缺点:
- 梯度消失。当x在0附近时,函数的导数比较大,也就是在更新的时候可以得到较大的调整,但是,当x远离0时,结果就会在0和1附近,梯度也基本上为0,神经元无法进行权值更新。此外,与这些神经元连接的神经元权值更新也会很小。这个问题称为梯度消失。
- 计量量比较大,尤其是指数函数计算。
2. Tanh激活函数
2.1 Tanh函数解析式
t a n h ( x ) = e x − e − x e x + e − x tanh(x) = \frac {e^x - e^{-x}} {e^x + e^{-x}} tanh(x)=ex+e−xex−e−x
其一阶导数:
t a n h ′ ( x ) = [ e x − e − x e x + e − x ] ′ = − ( e x + e − x ) ′ ( e x + e − x ) 2 ( e x − e − x ) + ( e x − e − x ) ′ e x + e − x = − ( e x − e − x ) ( e x + e − x ) 2 ( e x − e − x ) + ( e x + e − x ) e x + e − x = 1 − t a n h 2 ( x ) \begin{aligned} tanh'(x) &= [\frac {e^x - e^{-x}} {e^x + e^{-x}}]' \\ &= - \frac {(e^x + e^{-x})'} {(e^x + e^{-x})^2} (e^x - e^{-x}) + \frac {(e^x - e^{-x})'} {e^x + e^{-x}} \\ & = - \frac {(e^x - e^{-x})} {(e^x + e^{-x})^2} (e^x - e^{-x}) + \frac {(e^x + e^{-x})} {e^x + e^{-x}} \\ &= 1 - tanh^2(x) \end{aligned} tanh′(x)=[ex+e−xex−e−x]′=−(ex+e−x)2(ex+e−x)′(ex−e−x)+ex+e−x(ex−e−x)′=−(ex+e−x)2(ex−e−x)(ex−e−x)+ex+e−x(ex+e−x)=1−tanh2(x)
2.2 Tanh函数的代码实现
class Tanh(object):
"""
tanh 激活函数
"""
def __str__(self):
return 'Tanh'
def __call__(self, x):
return self.fn(x)
def fn(self, x):
"""$$tanh(x) = \frac {e^x - e^{-x}} {e^x + e^{-x}}$$"""
x = np.array(x)
return np.tanh(x)
def grad(self, x):
"""一阶导数: tanh'(x) = 1 - tanh ** 2"""
return 1 - self.fn(x) ** 2
2.3 Tanh函数的分析
tanh和sigmoid不同之处在于,sigmoid处在[0,1]之间,tanh处在[-1,1]之间。但是它们都没有解决梯度爆炸的问题。
3. ReLu-线性整流函数
3.1 ReLu函数解析式
f ( x ) = max ( 0 , x ) f(x) = \max(0, x) f(x)=max(0,x)
其一阶导数:
f ′ ( x ) { 1 , i f x > 0 0 , e l s e f'(x) \begin{cases} 1, &if\ x > 0\\ 0, &else \end{cases} f′(x){1,0,if x>0else
3.2 ReLu函数的代码实现
class ReLu(object):
"""
ReLu 激活函数
"""
def __str__(self):
return "ReLu"
def __call__(self, x):
return self.fn(x)
def fn(self, x):
"""f(x) = max (0, x)"""
x = np.array(x)
return np.clip(x, 0, np.inf)
def grad(self, x):
"""f'(x) = 1 if x > 0 else f'(x) = 0"""
x = np.array(x)
return (x > 0).astype(int)
3.3 ReLu函数的分析
优点:
- ReLu在x>0的时候,输出值也为x,所以在正数范围内对梯度消失有抵抗力;
- 在x<0的时候,输出为0,反向传播的过程中,结果也都会是0,计算效率高,并且使得网络稀疏,减少参数之间的相互依存关系,缓解过拟合问题的发生。
缺点:因为x<0时,输出为0,可以能导致神经元死亡, dying ReLu problem
4. Leaky ReLu - 泄漏Relu激活函数
4.1 Leaky ReLu 函数解析式
f ( x ) = max ( α x , x ) , α ∈ ( 0 , 1 ) f(x) = \max(\alpha x, x), \alpha \in (0, 1) f(x)=max(αx,x),α∈(0,1)
一阶导数:
f ′ ( x ) { 1 , i f x > 0 − α , e l s e f'(x) \begin{cases} 1, &if\ x > 0\\ -\alpha, &else \end{cases} f′(x){1,−α,if x>0else
4.2 Leaky ReLu 函数代码实现
class LeakyReLu(object):
def __init__(self, alpha=0.1):
self.alpha = alpha
def __str__(self):
return "LeakyReLu"
def __call__(self, x):
return self.fn(x)
def fn(self,x):
"""
f(x) = x, if x > 0
= alpha * x , if x <= 0
"""
x = np.array(x).astype(float)
x[x < 0]= x[x < 0] * self.alpha
return x
def grad(self, x):
"""
f'(x) = 1, if x > 0
= alpha, else
"""
x = np.array(x)
y = np.ones_like(x)
y[x < 0] *= self.alpha
return y
4.3 Leaky ReLu函数分析
Leaky relu就是为了解决ReLu会导致神经元思维而设计的,即便是在x<0的情况下,也给一个很小的斜率进行激活。
5. ELU
5.1 ELU函数解析式
f ( x ) = { x , i f x > 0 α ( e x − 1 ) , e l s e f(x) = \begin{cases} x, &if\ x > 0\\ \alpha(e^x - 1), &else \end{cases} f(x)={x,α(ex−1),if x>0else
一阶导数:
f ′ ( x ) = { 1 , i f x > 0 α e x , e l s e f'(x) = \begin{cases} 1, &if\ x > 0\\ \alpha e^x , &else \end{cases} f′(x)={1,αex,if x>0else
5.2 ELU函数代码实现
class ELU(object):
def __init__(self, alpha=1.0):
self.alpha = alpha
def __str__(self):
return 'ELU'
def __call__(self, x):
return self.fn(x)
def fn(self, x):
"""
f(x) = x, if x > 0
= alpha * (np.exp(x) - 1), else
"""
x = np.array(x).astype(float)
return np.where(x > 0, x, self.alpha * (np.exp(x) - 1))
def grad(self, x):
"""
f'(x) = 1, if x > 0
= alpha * np.exp(x) else
"""
x = np.array(x).astype(float)
return np.where(x > 0, np.ones_like(x), self.alpha * np.exp(x))
5.3 ELU函数分析
ELU也是针对RELU会导致神经元死亡的问题设计的,在x<0时有输出。不过ELU有指数运算问题。
6. SELU
6.1 SELU函数解析式
f ( x ) = λ { x , i f x > 0 α ( e x − 1 ) , e l s e f(x) = \lambda \begin{cases} x, &if\ x > 0\\ \alpha(e^x - 1), &else \end{cases} f(x)=λ{x,α(ex−1),if x>0else
一阶导数:
f ′ ( x ) = λ { 1 , i f x > 0 α e x , e l s e f'(x) = \lambda \begin{cases} 1, &if\ x > 0\\ \alpha e^x, &else \end{cases} f′(x)=λ{1,αex,if x>0else
6.2 SELU函数代码实现
class SELU(object):
def __init__(self):
self.alpha = 1.6732632423543772848170429916717
self.beta = 1.0507009873554804934193349852946
def __str__(self):
return "SELU"
def __call__(self, x):
return self.fn(x)
def fn(self, x):
"""
f(x) = beta * x, if x > 0
= beta * alpha * (np.exp(x) - 1), else
"""
x = np.array(x).astype(float)
return np.where(x > 0, x, self.alpha * (np.exp(x) - 1)) * self.beta
def grad(self, x):
"""
f'(x) = beta, if x > 0
= beta * alpha * np.exp(x) else
"""
x = np.array(x).astype(float)
return np.where(x > 0, np.ones_like(x), self.alpha * np.exp(x)) * self.beta
6.3 SELU函数分析
SELU就是在ELU前面乘了一个lambda,并且lambda>1, 可以通过调节lamda,调整参数更新的快慢,就可以调节输出的方差和均值。
参考资料:
https://blog.csdn.net/qq_30815237/article/details/86700680
https://github.com/ddbourgin/numpy-ml/tree/master/numpy_ml/neural_nets/activations