对于激活函数的应用是比较熟悉和频繁的,但一直以来没有系统性地把深度学习中地激活函数做一个总结,因此小知同学特地对常用的激活函数做一个比较全面的总结,在讲述理论的同时,也根据激活函数的公式进行编程实现
激活函数概念
所谓激活函数(Activation Function),就是在人工神经网络的神经元上运行的函数,负责将神经元的输入映射到输出端。
什么是激活函数
激活函数(Activation functions)对于人工神经网络模型去学习、理解非常复杂和非线性的函数来说具有十分重要的作用。它们将非线性特性引入到我们的网络中。如图1,在神经元中,输入的 inputs 通过加权,求和后,还被作用了一个函数,这个函数就是激活函数。引入激活函数是为了增
加神经网络模型的非线性。没有激活函数的每层都相当于矩阵相乘。就算你叠加了若干层之后,无非还是个矩阵相乘罢了。
为什么使用激活函数
如果不用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合,这种情况就是最原始的感知机(Perceptron)。
如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。
个人认知与理解
我觉得机器学习的传统算法与深度学习算法的比较重要的区别是:
- 从广义上来讲,机器学习的传统算法一般只能使用一种目标模型函数,比如逻辑回归使用logistic函数、只能解决单维度问题;而深度学习可以在不同神经层使用不同或者多种激活函数、因此拥有多种或者不同函数的特性,所以解决问题具有多维度、线性、非线性等处理能力
- 深度学习的激活函数使得深度学习算法既能解决简单的线性问题、也能处理复杂的非线性问题
- 数据中的特征往往具有不同的特性、特征与不同模型之间也有较大的辨识差异,机器学习的传统算法的单一模型可能只能对部分特征产生重要作用,而深度学习的多种激活函数则比较全面、多维度对特征进行学习
常用的激活函数
- sigmoid 函数
- tanh 函数
- relu 函数
- leaky relu 函数
- elu 函数
- softmax 函数
饱和激活函数与非饱和激活函数
- 饱和函数是指当自变量 x 达到某个值(或者说趋于无穷小、无穷大)的时候,因变量 y 就不再发生变化,而是趋于某一个固定的值
- sigmoid 函数就是一个饱和激活函数,当自变量 z 趋于无穷小时,因变量 y 趋于 0;当自变量 z 趋于无穷大时,因变量 y 趋于 1
- tanh 函数就是一个饱和激活函数,当自变量 z 趋于无穷小时,因变量 y 趋于 -1;当自变量 z 趋于无穷大时,因变量 y 趋于 1
- 饱和函数是指当自变量 x 达到某个值(或者说趋于无穷小、无穷大)的时候,因变量 y 就依然发生变化,并不是趋于某一个固定的值
- relu 函数就是一个非饱和激活函数,当自变量 z 小于 0 时,因变量 y 等于 0;但当自变量 z 大于 0 时,因变量 y 是一个 z 的变化值
- relu 的变种激活函数
- 非饱和激活函数的优势
- 首先,“非饱和激活函数”能解决所谓的“梯度消失”问题
- 其次,它能加快收敛速度
import warnings
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
warnings.filterwarnings('ignore')
%matplotlib inline
x = np.linspace(-10, 10, 100)
1.sigmoid激活函数(饱和函数)
- sigmoid函数计算公式
- sigmoid函数的导数公式
- sigmoid函数评价
- 优点:sigmoid函数有效地将实数域的线性问题映射到[0,1]区间的类别概率问题,实现分类;
- 缺点:然而在深度学习算法中使用sigmoid函数有时候在反向求导传播时会导致梯度消失的现象:
- 当z很大时,趋近于1,当z很小时,趋近于0
- 其导数 在z很大或很小时都会趋近于0,造成梯度消失的现象
# 手写计算函数
def sigmoid(z, mode=False):
if mode: # 手写公式
L = []
for i in range(len(z)):
sigmoid_value = 1/(1+(2.7183)**(-z[i]))
L.append(sigmoid_value)
return L
else: # 使用numpy
return 1/(1+np.exp(-z))
plt.plot(x, sigmoid(z=x))
# 调用 Tensorflow 的 sigmoid 函数
y_sigmoid = tf.nn.sigmoid(x)
plt.plot(x, y_sigmoid)
2.tanh激活函数(饱和函数)
- tanh函数计算公式
- tanh函数的导数公式
- tanh函数评价
- 优点:sigmoid函数有效地将实数域的线性问题映射到[-1,1]区间的类别概率问题,实现分类;
- 缺点:然而在深度学习算法中使用tanh函数有时候在反向求导传播时会导致梯度消失的现象:
- 当z很大时,趋近于1,当z很小时,趋近于-1
- 其导数 在z很大或很小时都会趋近于0,造成梯度消失的现象
- tanh与sigmoid的关系式:
def tanh(z, mode=True):
if mode: # 手写公式
L = []
for i in range(len(z)):
exp1 = 2.7183**(z[i])
exp2 = 2.7183**(-z[i])
tanh_value = (exp1-exp2)/(exp1+exp2)
L.append(tanh_value)
return L
else: # 使用numpy
return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))
plt.plot(x,tanh(z=x))
# 调用 Tensorflow 的 tanh 函数
y_tanh = tf.nn.tanh(x)
plt.plot(x, y_tanh)
3.relu激活函数(非饱和函数)
修正线性单元(Rectified linear unit,ReLU)
- relu函数计算公式
- relu函数的导数公式
- relu函数评价
- 优点:
- relu函数的非饱和性可以有效地解决梯度消失的问题,提供相对较宽的激活边界
- relu函数是阈值函数,运算简单且快速,只需通过阈值判断就可以得到激活值,而sigmoid、tanh函数都需要计算指数,运算复杂
- ReLU的单侧抑制(负梯度都为 0)提供了网络的稀疏表达能力
- 缺点:
- 会导致负梯度的神经元产生不可逆的死亡,也称为死亡神经元,由于负梯度值都为 0,在往后的运算中都将以 0 传播
- 如果学习率(Learning Rate)设置较大,会导致超过一定比例的神经元不可逆死亡,进而参数梯度无法更新,整个训练过程失败
- 优点:
def relu(x): # 手写公式
relu_list = []
for i in range(len(x)):
relu_list.append(max(0, x[i]))
return relu_list
plt.ylim(-1,6)
plt.plot(x, relu(x))
# 调用 Tensorflow 的 relu 函数
y_relu = tf.nn.relu(x)
plt.ylim(-1,6)
plt.plot(x, y_relu)
4.leaky relu
带泄露修正线性单元(Leaky ReLU)函数是经典(以及广泛使用的)的ReLu激活函数的变体,该函数输出对负值输入有很小的坡度,它旨在解决负梯度神经元死亡的问题。由于负梯度神经元导数总是不为零,这能减少静默神经元的出现,允许基于梯度的学习(虽然会很慢),解决了Relu函数进入负区间后神经元不学习的问题。
- leaky relu 函数计算公式
- leaky relu 函数的导数公式
- leaky relu 函数评价
- 优点:
- 旨在解决 relu 负梯度神经元死亡的问题,函数输出对负值输入有很小的坡度
- 解决了Relu函数进入负区间后神经元不学习的问题
- 缺点:
- 负梯度的 a 难以寻求合适的系数值,a 通常小于 1 且通常使用 a = 0.1
- 负梯度的 a 的选择和确定需要一定的经验或者做实验验证,相对麻烦一些
- 优点:
def leaky_rule(z): # 手写公式
L = []
for i in range(len(z)):
lrule_value = max(0.1*z[i], z[i])
L.append(lrule_value)
return L
plt.plot(x, leaky_rule(z=x))
# 调用 Tensorflow 的 leaky_relu 函数
y_lrelu = tf.nn.leaky_relu(x)
plt.plot(x, y_lrelu)
5.elu
指数线性单元(Exponential Linear Units)
-
elu 函数计算公式
-
elu 函数的导数公式
-
elu 函数评价
- 融合了sigmoid和ReLU,左侧具有软饱和性,右侧无饱和性。
- 右侧线性部分使得ELU能够缓解梯度消失,而左侧软饱能够让ELU对输入变化或噪声更鲁棒。
- ELU的输出均值接近于零,所以收敛速度更快。
- 在 ImageNet上,不加 Batch Normalization 30 层以上的 ReLU 网络会无法收敛,PReLU网络在MSRA的Fan-in (caffe )初始化下会发散,而 ELU 网络在Fan-in/Fan-out下都能收敛。
def elu(z, a=0.1): # 手写公式
L = []
for i in range(len(z)):
if z[i] >= 0:
elu_value = z[i]
L.append(elu_value)
else:
elu_value = a*(2.7183**(z[i]) - 1)
L.append(elu_value)
return L
plt.plot(x, elu(z=x, a=1))
# 调用 Tensorflow 的 elu 函数
y_elu = tf.nn.elu(x)
plt.plot(x, y_elu)
参考资料
[1] 百度百科,激活函数,https://baike.baidu.com/item/%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0/2520792?fr=aladdin
[2] 百面机器学习,深度神经网络中的激活函数
[3] CSDN博客,常用激活函数,https://blog.csdn.net/qq_23304241/article/details/80300149
[4] CSDN博客,ELU激活函数, https://blog.csdn.net/zrh_CSDN/article/details/81266188
来源:CSDN
作者:小知&AI干货分享
链接:https://blog.csdn.net/qq_41731978/article/details/103822468