【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。

激活函数的作用

为卷积神经网络提供非线性

1、Sigmoid激活函数

Sigmoid激活函数是常用的连续、平滑的“s”型激活函数,其数学定义比较简单,如公式1所示:

【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
简单来说,Sigmoid函数以实数输入映射到(0,1)区间,用来做二分类。对于一个极大的负值输入,它输出的值接近于0;对于一个极大的正值输入,它输出的值接近于1。
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
Sigmoid激活函数曾一度被不同的网络使用,从Sigmoid及其导数曲线图可知,当输入的值非常小或者非常大时,其Sigmoid输出的值接近0或者1,当Sigmoid函数的前一层梯度接近于0时,由于前一层的学习参数梯度接近于0,使得参数无法得到有效更新,从而产生饱和神经元,因此Sigmoid激活函数在网络使用中比较容易产生梯度消失问题,饱和的神经元会加重梯度消失问题。在神经网络训练过程中,常需要对Sigmoid的值进行幂计算,增加训练时长,此外Sigmoid不是关于原点中心对称的,使得收敛变慢。

2、tanh激活函数

非线性函数tanh成为双曲线正切函数,其数学表达式见公式2:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。

简单的说,tanh激活函数可以将实数映射到(-1,1)区间,当tanh的输出极值接近-1和1时,也面临梯度饱和的问题。图2所示为tanh激活函数及其导数曲线图:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
由曲线图可知,tanh激活函数是关于原点中心对称的,相比Sigmoid而言,收敛速度加快,梯度消失的特点依旧存在,因此难以训练。尽管tanh激活函数和Sigmoid激活函数存在梯度消失问题,但是梯度过大就会导致梯度爆炸问题。

3、ReLU激活函数

近年来ReLU激活函数变得很受欢迎,我们几乎可以在很多神经网络架构中看到ReLU的应用。其数学表达式见公式3:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
简单来说,ReLU将所有负值取作0,正值保持不变。图3所示为ReLU激活函数及其导数曲线图
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
ReLU会使一部分神经元的输出为0,这样就造成了 网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。使用ReLU激活函数有助于优化器更快的找到正确的权重集合,理论上它使随机梯度下降收敛得更快。ReLU激活函数的计算成本低,因为只是判断了阈值。ReLU有个缺点,当一个很大的梯度进行反向传播时,流经的神经元经常会变得无效,这些神经元称为无效神经元,可以通过谨慎选择学习率控制。

4、Leaky ReLU激活函数

Leaky ReLU的提出就是为了解决神经元“死亡”问题,Leaky ReLU与ReLU很相似,仅在输入小于0的部分有差别,ReLU输入小于0的部分值都为0,而LeakyReLU输入小于0的部分,值为负,且有微小的梯度。其数学表达式见公式4:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
通常取0.01,图4所示为Leaky ReLU激活函数及其导数曲线图
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
使用Leaky ReLU作为激活函数的优点就是在反向传播过程中也可以计算输入小于零部分的梯度,而不是像ReLU激活函数对于输入小于零部分的计算得到的梯度值为0,这样就避免了梯度方向锯齿问题。

5、Softplus激活函数

Softplus激活函数曲线类似ReLU激活函数曲线,但Softplus激活函数曲线相对平滑许多。其数学表达式见公式5:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
图5所示为Softplus激活函数及其导数曲线图:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
可以看出,Softplus可以被视为ReLU的平滑。根据神经科学家的相关研究,Softplus和ReLU类似于大脑神经元的激活频率功能。换句话说,与早期的激活函数相比,Softplus和ReLU更接近大脑神经元的激活模型。优点:Softplus可以作为ReLU的一个不错的替代选择,可以看到与ReLU不同的是,Softplus的导数是连续的、非零的、无处不在的,这一特性可以防止出现ReLU中的“神经元死亡”现象。缺点:Softplus是不对称的,不以0为中心,存在偏移现象;而且,由于其导数常常小于1,也可能会出现梯度消失的问题。

6、hardswish激活函数

hardswish激活函数。在MobileNet v3中被提出,相较于swish函数,具有数值稳定性好,计算速度快等优点。其数学表达式见公式6:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
图6所示为hardswish激活函数及其导数曲线图
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
hardswish激活函数是对swish激活函数 的改进,因为swish非线性激活函数作为ReLU非线性激活函数的替代,在一定程度上可以提高神经网络的准确性。尽管swish非线性激活函数提高了检测精度,但不适合在嵌入式移动设备上使用,因为“S”型函数在嵌入式移动设备上的计算成本更高,求导较为复杂,在量化时计算较慢。在实验中使用hardswish非线性激活函数在准确性上没有明显差别,但从部署在嵌入式移动设备上而言具有多重优势。首先,几乎所有软件和硬件框架都提供了ReLU的优化实现。其次,在量化模式下,它消除了由于近似Sigmoid形的不同实现而导致的潜在数值精度损失。最后,在实践中,hardswish激活函数可以实现为分段功能,以减少内存访问次数,从而大大降低了等待时间成本。

7、Mish激活函数

Mish激活函数是Diganta Misra等人提出的一种平滑的非单调的激活函数。其数学表达式见7、8、9所示:
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
其函数曲线如图7所示
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。
Mish激活函数主要有一下四个特点:无上界、无下界、光滑、非单调。这四个特性提高了函数的性能。无上限:它可以防止网络饱和,即梯度消失。有下界:提高网络的正则化效果。平滑:首先,与ReLU相比,在0值点连续可以减少一些不可预测的问题。其次,它可以使网络更容易优化,提高泛化性能,一些较小的负输入可以保留为负输出,以提高网络的可解释性和梯度流。
8、总结
激活函数的作用将将输入映射到输出,为神经网络提供非线性。激活函数选用是否恰当,直接影响网络的性能,比如收敛速度、检测精度、泛化性能等。图2-13展示了以上所述激活函数的曲线对比图。
【深度学习】之激活函数篇[Sigmoid、tanh、ReLU、Leaky ReLU、Mish、Hardswish、SiLU]附绘图Python代码。

9、代码绘图

代码仅仅是根据公式和求导进行绘图的。仅供参考:
注意阅读代码,选择需要绘制的激活函数的代码段运行,其余不用的注释掉即可

# -*- coding : UTF-8 -*-
import math
import numpy as np
import matplotlib.pyplot as plt
from math import exp

# set x's range
x = np.arange(-100, 100, 0.1)

y1 = 1 / (1 + math.e ** (-x))  # sigmoid
y11 = 1 / (2 + math.e ** (-x) + math.e ** (x))  # sigmoid的导数

y2 = (math.e ** (x) - math.e ** (-x)) / (math.e ** (x) + math.e ** (-x))  # tanh
y22 = 1 - y2 * y2  # tanh函数的导数

y3 = np.where(x < 0, 0, x)  # relu
y33 = np.where(x < 0, 0, 1)  # ReLU函数导数

y4 = np.where(x < 0, 0.01*x, x) #Leaky ReLU
y44 = np.where(x < 0, 0.01, 1)  #Leaky ReLU导数

y5 = np.log(np.exp(x) + 1)   #softplus
y55 = math.e ** (x) / (1+math.e ** (x))

y6 = np.where(x <= -3, 0,np.where(x >= 3,x,x*(x+3)/6))  #hardswish
y66 = np.where(x <= -3, 0, np.where(x >= 3, 1, (2*x)/6))

y7 = x * (np.exp(y5)-np.exp(-y5))/(np.exp(y5)+np.exp(-y5))


plt.xlim(-5, 5)
plt.ylim(-2, 2)

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.spines['bottom'].set_position(('data', 0))
ax.spines['left'].set_position(('data', 0))

# Draw pic
#plt.plot(x, y1, label='Sigmoid', linestyle="-", color="red")
#plt.plot(x, y11, label='Sigmoid derivative', linestyle="-", color="violet")

#plt.plot(x, y2, label='Tanh', linestyle="-", color="blue")
#plt.plot(x, y22, label='Tanh derivative', linestyle="-", color="violet")
#
plt.plot(x, y3, label='Relu', linestyle="-", color="green")
plt.plot(x, y33, label='Relu derivative', linestyle="-", color="violet")

#plt.plot(x, y4, label='Leaky ReLU', linestyle="-", color="olive")
#plt.plot(x, y44, label='Leaky ReLU derivative', linestyle="-", color="orangered")

#plt.plot(x, y5, label='Softplus', linestyle="-", color="dimgrey")
#plt.plot(x, y55, label='Softplus derivative', linestyle="-", color="rosybrown")

#plt.plot(x, y6, label='Softplus', linestyle="-", color="purple")
#plt.plot(x, y66, label='Softplus derivative', linestyle="-", color="deeppink")

#plt.plot(x, y7, label='Mish', linestyle="-", color="k")


# Title
plt.legend(['Sigmoid', 'Tanh', 'Relu', 'Leaky ReLU', 'Softplus','hardswish','Mish'])
#plt.legend(['Sigmoid', 'Sigmoid derivative'])  # y1 y11
#plt.legend(['Tanh', 'Tanh derivative'])  # y2 y22
plt.legend(['Relu', 'Relu derivative'])  # y3 y33
#plt.legend(['Leaky ReLU', 'Leaky ReLU derivative'])  # y4 y44
#plt.legend(['Mish', 'Mish derivative'])  # y5 y55


# plt.legend(['Sigmoid', 'Sigmoid derivative', 'Relu', 'Relu derivative', 'Tanh', 'Tanh derivative'])  # y3 y33
# plt.legend(loc='upper left')  # 将图例放在左上角

# save pic
plt.savefig('plot_test.png', dpi=100)
plt.savefig(r"D:\desktop\activation_plot\ReLU")

# show it!!
plt.show()

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年3月30日
下一篇 2023年4月5日

相关推荐