学习资源站

14-更换激活函数之SiLU,ReLU,ELU,Hardswish,Mish,Softplus,AconC系列等_olov5改进系列(13)——更换激活函数之silu,relu,elu,hardswish,…

YOLOv5改进系列(13)——更换激活函数之SiLU,ReLU,ELU,Hardswish,Mish,Softplus,AconC系列等

🌲一、激活函数的简介

1.1 什么是激活函数?

在接触到深度学习(Deep Learning)后,特别是神经网络中,我们会发现在每一层的神经网络输出后都会使用一个函数(比如sigmoid,tanh,Relu等等)对结果进行运算,这个函数就是激活函数(Activation Function)。那么为什么需要添加激活函数呢?如果不添加又会产生什么问题呢?

首先,我们知道神经网络模拟了人类神经元的工作机理,激活函数(Activation Function)是一种添加到人工神经网络中的函数,旨在帮助网络学习数据中的复杂模式。在神经元中,输入的input经过一系列加权求和后作用于另一个函数,这个函数就是这里的激活函数激活函数是一种特殊的非线性函数,它能够在神经网络中使用,其作用是将输入信号转化成输出信号。类似于人类大脑中基于神经元的模型,它将神经元中的输入信号转换为一个有意义的输出,从而使得神经网络能够学习和识别复杂的模式。激活函数最终决定了是否传递信号以及要发射给下一个神经元的内容。在人工神经网络中,一个节点的激活函数定义了该节点在给定的输入或输入集合下的输出。

激活函数可以分为线性激活函数以及非线性激活函数常用的激活函数有 Sigmoid、ReLU、Leaky ReLU 和 ELU 等。

在这里插入图片描述


1.2 激活函数有什么用?

一句话总结:为了提高模型的表达能力。

激活函数能让中间输出多样化,从而能够处理更复杂的问题。如果不使用激活函数,那么每一层的输出都是上一层输入的线性函数,最后的输出也只是最开始输入数据的线性组合而已。而激活函数可以给神经元引入非线性因素,当加入到多层神经网络时,就可以让神经网络拟合任何线性函数或非线性函数,从而使得网络可以适合更多的非线性问题,而不仅仅是线性问题

激活函数被定义为一个几乎处处可微的函数。


🌲二、一些常见的激活函数

🌻2.1 sigmoid函数

sigmoid 是使用范围最广的一类激活函数,具有指数函数形状,它在物理意义上最为接近生物神经元,是一个在生物学中常见的S型的函数,也称为S型生长曲线。此外,(0, 1) 的输出还可以被表示作概率,或用于输入的归一化,代表性的如Sigmoid交叉熵损失函数。

函数的表达式如下:

图像如下:

sigmoid优点:

(1) 值域在0和1之间

(2)函数具有非常好的对称性

(3)sigmoid的优点在于输出范围有限,所以数据在传递的过程中不容易发散。当然也有相应的缺点,就是饱和的时候梯度太小

(4)求导容易

sigmoid缺点:

(1)容易出现梯度消失

(2)函数输出并不是zero-centered(零均值)

(3)幂运算相对来讲比较耗时


🌻2.2 tanh / 双曲正切激活函数

tanh激活函数又叫作双曲正切激活函数,在sigmoid基础上做出改进,与sigmoid相比,tanh输出均值为0,能够加快网络的收敛速度。然而,tanh同样存在梯度消失现象。

函数的表达式如下:

图像如下:

tanh优点:

(1)当输入较大或较小时,输出几乎是平滑的并且梯度较小,这不利于权重更新。tanh 的输出间隔为 1,并且整个函数以 0 为中心,比 sigmoid 函数更好

(2)在 tanh 图中,负输入将被强映射为负,而零输入被映射为接近零

tanh缺点:

(1)仍然存在梯度饱和的问题

(2)依然进行的是指数运算


🌻2.3 ReLU激活函数

ReLU函数又称为修正线性单元(Rectified Linear Unit),是一种分段线性函数,通常指代以斜坡函数及其变种为代表的非线性函数。其弥补了sigmoid函数以及tanh函数的梯度消失问题,在目前的深度神经网络中被广泛使用。

函数的表达式如下:

图像如下:

ReLU优点: 

(1)当输入为正时,导数为1,一定程度上改善了梯度消失问题加速梯度下降的收敛速度

(2)计算速度快得多。ReLU 函数中只存在线性关系,因此它的计算速度比 sigmoid 和 tanh 更快

(3)被认为具有生物学合理性(Biological Plausibility),比如单侧抑制、宽兴奋边界(即兴奋程度可以非常高)

ReLU缺点:

(1)当输入为负时,ReLU 完全失效,在正向传播过程中,这不是问题。有些区域很敏感,有些则不敏感。但是在反向传播过程中,如果输入负数,则梯度将完全为零

(2)不以零为中心:和 Sigmoid 激活函数类似,ReLU 函数的输出不以零为中心,ReLU 函数的输出为 0 或正数,给后一层的神经网络引入偏置偏移,会影响梯度下降的效率 


🌻2.4 SiLU 

SiLU激活函数(又称Sigmoid-weighted Linear Unit)是一种新型的非线性激活函数,它是Sigmoid和ReLU的改进版。SiLU具备无上界有下界、平滑、非单调的特性。SiLU在深层模型上的效果优于 ReLU。可以看做是平滑的ReLU激活函数。SiLU激活函数的特征是它在低数值区域中表现较为平滑,而在高数值区域中表现起来十分“锐利”,从而能够有效地避免过度学习的问题。

函数的表达式如下:

图像如下:

在这里插入图片描述

SiLU优点:

(1)相对于ReLU函数,SiLU函数在接近零时具有更平滑的曲线,并且由于其使用了sigmoid函数,可以使网络的输出范围在0和1之间

SiLU缺点:

(1)引入了指数函数,增加了计算量。


🌻2.5 swish激活函数

swish 是一个平滑的、非单调的函数,在深度网络上始终匹配或优于 ReLU,适用于各种具有挑战性的领域,如图像分类和机器翻译。通过self-gating,它只需要一个标量输入,而在多选通场景中,它需要多个双标量输入。

函数的表达式如下:

图像如下:

swish优点:

(1)无上界(避免过拟合)

(2)有下界(产生更强的正则化效果)

(3)平滑(处处可导 更容易训练)

(4)x<0具有非单调性(对分布有重要意义 这点也是Swish和ReLU的最大区别)


🌻2.6 hardswish激活函数

hardswish激活函数是对swish激活函数的改进,尽管swish非线性激活函数提高了检测精度,但不适合在嵌入式移动设备上使用,因为“S”型函数在嵌入式移动设备上的计算成本更高,求导较为复杂,在量化时计算较慢。但是如果在实验中使用hardswish非线性激活函数在准确性没差别的情况下部署在嵌入式移动设备上却会具有多重优势。

函数的表达式如下:

图像如下:

 hardswish优点:

(1)hardswish相较于swish函数,具有数值稳定性好计算速度快等优点

(2)消除了由于近似Sigmoid形的不同实现而导致的潜在数值精度损失

(3)在实践中,hardswish激活函数可以实现为分段功能,以减少内存访问次数,从而大大降低了等待时间成本


🌻2.7 Mish激活函数

Mish一种新型的自正则化的非单调激活函数,拥有无上界(unbounded above)、有下界(bounded below)、平滑(smooth)和非单调(nonmonotonic)四个优点。其在ImageNet上的效果比ReLU和Swish都要好。

函数的表达式如下:

图像如下:

 Mish优点:

(1)没有上限

(2)有下限

(3)非单调性

(4)无穷阶连续性和光滑性


🌻2.8 ELU激活函数

ELU(Exponential Linear Unit)激活函数是一种添加了指数项的非线性激活函数,ELU 激活函数的特征在于输入为负时会有正值的输出而不是 0。这样可以有效地避免神经元死亡问题。 ELU 激活函数有助于神经元学习复杂的非线性函数,可以帮助神经元学习复杂的非线性特征。
 

函数的表达式如下:

图像如下: 

 ELU优点: 

(1)不会有Dead ReLU问题

(2)输出的均值接近0。 能得到负值输出,这能帮助网络向正确的方向推动权重和偏置变化

ELU缺点:

(1)由于包含指数运算,所以计算量稍大

(2)无法避免梯度爆炸问题

(3)神经网络不学习 α 值


🌻2.9 AconC/MetaAconC激活函数

这是2021年新出的一个激活函数,先从ReLU函数出发,采用Smoth maximum近似平滑公式证明了Swish就是ReLU函数的近似平滑表示,这也算提出一种新颖的Swish函数解释(Swish不再是一个黑盒)。之后进一步分析ReLU的一般形式Maxout系列激活函数,再次利用Smoth maximum将Maxout系列扩展得到简单且有效的ACON系列激活函数:ACON-A、ACON-B、ACON-C。最终提出meta-ACON,动态的学习(自适应)激活函数的线性/非线性,显著提高了表现。

函数的表达式如下:

 图像如下: 

在这里插入图片描述

  AconC/MetaAconC优点: 

(1)动态的学习(自适应)激活函数的线性/非线性,显著提高了表现

(2)ACON的参数P1和P2负责控制函数的上下限,也就是允许神经元自适应激活或者不激活,这个动态控制函数线性与非线性能力的参数就可以进行一个自适应学习


🌻2.10 Softplus激活函数

Softplus函数可以看作是ReLU函数的平滑。根据神经科学家的相关研究,Softplus函数和ReLU函数与脑神经元激活频率函数有神似的地方。也就是说,相比于早期的激活函数,Softplus函数和ReLU函数更加接近脑神经元的激活模型,而神经网络正是基于脑神经科学发展而来,这两个激活函数的应用促成了神经网络研究的新浪潮。

函数的表达式如下:

图像如下:

Softplus优点: 

(1)对于有些输出,需要更加平滑和连续性,而 Softplus相对于Relu,是一种更加平滑的激活函数

Softplus缺点:

(1)计算复杂,涉及到e的指数计算,计算量大

(2)这个函数对于硬件化也不友好


🌲三、更换激活函数的步骤

第①步 打开activations.py文件,查看已有函数

首先我们找到utils/activations.py文件,位置如下图所示:

打开这个文件,我们可以发现,SiLU,Hardswish,Mish,MemoryEfficientMish,FReLU,AconC,MetaAconC  已经在文件里定义了,这是我们可以直接用的。


第②步 在common.py中更换激活函数 

先导入要更换的函数,这里以MetaAconC为例:

from utils.activations import MetaAconC

然后再在相应位置修改,如下图所示:

如果想更换其他激活函数,也可以参照下面代码,步骤都是一样的:

  1. class Conv(nn.Module):
  2. # Standard convolution
  3. def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
  4. super().__init__()
  5. self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
  6. self.bn = nn.BatchNorm2d(c2)
  7. #self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  8. # self.act = nn.Identity() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  9. # self.act = nn.Tanh() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  10. # self.act = nn.Sigmoid() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  11. # self.act = nn.ReLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  12. # self.act = nn.LeakyReLU(0.1) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  13. # self.act = nn.Hardswish() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  14. # self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  15. # self.act = Mish() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  16. # self.act = FReLU(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  17. # self.act = AconC(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  18. self.act = MetaAconC(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  19. # self.act = SiLU_beta(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  20. #self.act = FReLU_noBN_biasFalse(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  21. # self.act = FReLU_noBN_biasTrue(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
  22. def forward(self, x):
  23. return self.act(self.bn(self.conv(x)))
  24. def forward_fuse(self, x):
  25. return self.act(self.conv(x))

🌲四、如何选择合适的激活函数

其实关于激活函数的选择是调参中的玄学,不同的数据集效果不同,以下是我参考一些资料总结的一点经验,也欢迎大家在评论区补充噢!

  1. 小白可以从ReLU函数开始,如果ReLU函数没有提供最优结果,再尝试其他激活函数。
  2. 如果使用 ReLU,那么一定要小心设置 learning rate,而且要注意不要让网络出现很多 dead神经元,如果出现这个问题,那么可以试试 Leaky ReLU、PReLU 或者 Maxout(貌似PReLU效果最好)。
  3. ReLU函数只能在隐藏层中使用。
  4. 在搭建神经网络时,如果搭建的神经网络层数不多,选择 Sigmoid、Tanh、ReLU,LeakyReLU,Softmax 都可以;而如果搭建的网络层次较多,那就需要小心,选择不当就可导致梯度消失问题。
  5. 由于梯度消失问题,有时要避免使用sigmoid和tanh函数。
  6. 用于分类器时,Sigmoid函数及其组合通常效果更好。(除非在二分类问题中,否则请小心使用Sigmoid函数)