前言:Hello大家好,我是小哥谈。激活函数(Activation functions)对于人工神经网络模型去学习、理解非常复杂和非线性的函数具有十分重要的作用。YOLOv5模型训练过程中即使用了激活函数,可以改善模型的训练速度和准确性。本节课就给大家介绍一下激活函数的概念以及常见的激活函数。🌈
前期回顾:
YOLOv5基础知识入门(1)— YOLO算法的发展历程
YOLOv5基础知识入门(2)— YOLOv5核心基础知识讲解
YOLOv5基础知识入门(3)— 目标检测相关知识点
YOLOv5基础知识入门(4)— 神经网络的基本概念与原理
YOLOv5基础知识入门(5)— 损失函数(IoU、GIoU、DIoU、CIoU和EIoU)
目录
🚀1.激活函数的概念
🚀2.引入激活函数的目的
🚀3.常见的激活函数
💥💥3.1 Mish
💥💥3.2 Sigmoid
💥💥3.3 Tanh
💥💥3.4 ReLU
💥💥3.5 LeakyReLU
💥💥3.6 Softmax
💥💥3.7 SiLU
🚀4.激活函数性质
🚀5.如何选择激活函数
🚀1.激活函数的概念
激活函数(Activation functions)对于人工神经网络模型去学习、理解非常复杂和非线性的函数来说具有十分重要的作用。它们将非线性特性引入到神经网络中。在下图中,输入的inputs 通过加权、求和后,还被作用了一个函数 f,这个函数 f 就是激活函数。引入激活函数的作用是为了增加神经网络模型的非线性。🌱
激活函数是非线性函数,主要是因为线性函数的组合依然是一个线性函数,而神经网络需要引入非线性映射才能学习复杂的函数关系。如果神经网络中的激活函数是线性函数,那么整个神经网络就是由线性组合构成的,其输出也必然是一个线性函数。因此,无论神经网络有多少层,它都只能学习线性函数关系。在这种情况下,神经网络的表达能力就会大大降低,无法处理非线性问题。而通过引入非线性激活函数,神经网络就可以引入非线性映射,从而能够学习更加复杂的函数关系。非线性激活函数可以将神经元的输入映射到一个非线性空间中,使得神经网络可以学习复杂的函数关系,比如图像和语音等高维非线性数据的特征表达。因此,激活函数的非线性特性是神经网络能够处理非线性问题的关键。 🍂
🚀2.引入激活函数的目的
在神经网络中,激活函数是一个重要的组成部分,其主要作用是为网络引入非线性特性。神经网络中的每一层都由一组神经元组成,每个神经元接收前一层的输入,并计算加权和。如果网络中没有激活函数,那么神经网络就会变成一个线性模型,无法学习复杂的非线性函数关系。🍀
激活函数的引入可以让神经网络具备非线性映射的能力,从而能够学习更加复杂的函数关系。通过引入激活函数,神经元的输出被映射到一个非线性空间中,使得神经网络可以学习更加复杂的模型和特征,从而提高模型的表达能力和泛化能力。🌹
此外,激活函数还可以对神经元的输出进行限制,例如限制在某个范围内,从而避免神经元输出的过大或过小,导致梯度消失或梯度爆炸的问题。因此,引入激活函数可以使神经网络具备非线性映射能力,提高模型的表达能力和泛化能力。💗
🚀3.常见的激活函数
💥💥3.1 Mish
Mish激活函数是一种新型的激活函数,它是由Diganta Misra在2019年提出的。与传统的激活函数相比,Mish激活函数具有更好的性能和更快的收敛速度。
它的公式为:
m = nn.Mish()
input = torch.randn(2)
output = m(input)
与其他常用的激活函数相比,Mish激活函数具有以下特点:
☘️(1)具有自适应性:在输入值较小时,Mish函数类似于线性函数,这有助于模型在学习初期更快地收敛;在输入值较大时,Mish函数类似于ReLU函数,这有助于提高模型的表达能力。
☘️(2)具有平滑性:Mish函数的导数具有连续性和平滑性,这可以避免由于梯度突变导致的不稳定性等问题。
☘️(3)具有性能优势:与其他常用的激活函数相比,Mish函数在多个深度学习任务中表现出了更好的性能,如图像分类、目标检测、语音识别等任务。
总之,Mish激活函数是一种具有自适应性、平滑性和性能优势的激活函数,可以在深度学习中发挥重要作用。🐳
说明:♨️♨️♨️
Mish激活函数是2019年下半年提出的激活函数。
论文地址:Mish: A Self Regularized Non-Monotonic Activation Function
💥💥3.2 Sigmoid
Sigmoid函数的取值范围是(0,1),输入越大,输出越接近于1;输入越小,输出越接近于0。这意味着,Sigmoid函数可以将任意实数值映射到一个(0,1)的区间内,可以看做是一个概率分布,表示样本属于某一类的概率。
它的公式为:
m = nn.Sigmoid()
input = torch.randn(2)
output = m(input)
Sigmoid函数具有以下特点:
☘️(1)具有平滑性:对输入的变化相对平滑,对神经网络的优化过程有帮助。
☘️(2)易于求导:方便在反向传播时计算梯度,用于优化神经网络参数。
☘️(3)输出范围为(0,1),可以表示概率值。
但是Sigmoid函数也存在以下缺点:
☘️(1)在输入较大或者较小的情况下,Sigmoid函数的梯度接近于0,容易导致梯度消失的问题。
☘️(2)Sigmoid函数的输出不是以0为中心的,这会导致神经元的输出偏向于某个方向,可能会影响神经网络的收敛速度。
由于Sigmoid函数存在上述缺点,现在较少在深度神经网络中使用。通常情况下,ReLU和其变种是更好的选择。🐳
💥💥3.3 Tanh
Tanh函数,也称为双曲正切函数(Hyperbolic Tangent),是一种常用的激活函数。它在数学上是Sigmoid函数的变换版本,与Sigmoid函数类似,主要用于二分类问题。
Tanh函数的取值范围是(-1,1),输入越大,输出越接近于1;输入越小,输出越接近于-1。因此,Tanh函数可以将任意实数值映射到一个(-1,1)的区间内。
它的公式为:
m = nn.Tanh()
input = torch.randn(2)
output = m(input)
Tanh函数具有以下优点:
☘️(1)具有平滑性:对输入的变化相对平滑,对神经网络的优化过程有帮助。
☘️(2)易于求导:方便在反向传播时计算梯度,易于优化神经网络参数。
☘️(3)输出范围为(-1,1),可以表示正负激活。
与Sigmoid函数相比,Tanh函数的主要优势是它的输出是以0为中心的,因此可以避免偏置问题。然而,它也存在梯度消失的问题,对于输入较大或者较小的情况,梯度也会接近于0。
由于Tanh函数也存在梯度消失的问题,现在通常使用ReLU及其变种作为深度深度神经网络的激活函数。🐳
💥💥3.4 ReLU
ReLU(Rectified Linear Unit)是一种常用的非线性激活函数,它被广泛应用于深度神经网络中。ReLU函数在输入为正数的时候,直接输出该值;在输入为负数的时候,输出为0。
它的公式为:
m = nn.ReLU()
input = torch.randn(2)
output = m(input)
An implementation of CReLU - https://arxiv.org/abs/1603.05201
m = nn.ReLU()
input = torch.randn(2).unsqueeze(0)
output = torch.cat((m(input),m(-input)))
ReLU函数的优点如下:
☘️(1)计算速度快:ReLU函数只需要简单的数值比较和取最大值运算,因此计算速度非常快。
☘️(2)梯度计算简单:ReLU函数在x>0时的导数为1,在x<0时的导数为0,因此计算简单,有助于避免梯度消失的问题。
☘️(3)收敛速度快:ReLU函数能够有效地避免梯度消失的问题,因此可以使神经网络更快地收敛。
然而,ReLU函数也存在一些问题:
☘️(1)Dead ReLU问题:当输入的x≤0时,ReLU函数的导数为0,因此梯度更新为0,这种现象称为Dead ReLU问题。当大量神经元出现Dead ReLU问题时,神经网络的表现会受到严重影响。
☘️(2)输出不是以0为中心:ReLU函数的输出在x>0时为x,因此输出的分布不是以0为中心,可能会导致优化困难。
针对Dead ReLU问题,现有的一些改进方法包括LeakyReLU、PReLU和ELU等。针对输出不是以0为中心的问题,可以使用Batch Normalization等方法进行处理。🐳
💥💥3.5 LeakyReLU
LeakyReLU(Leaky Rectified Linear Unit)是对ReLU激活函数的改进,是一种专门设计用于解决Dead ReLU问题的激活函数。
它的公式为:
m = nn.LeakyReLU(0.1)
input = torch.randn(2)
output = m(input)
LeakyReLU函数相对于ReLU函数的优点如下:
☘️(1)避免Dead ReLU问题:当输入的x≤0时,LeakyReLU函数的导数为0.01,因此梯度不会消失,避免了Dead ReLU问题的出现。
☘️(2)降低输出的偏置:由于LeakyReLU函数在输入≤0时的输出是一个较小的值,因此输出的分布更加均匀,有助于降低偏置。
需要注意的是,LeakyReLU函数可能会使得神经网络的训练时间增加,因此它增加了一个超参数Leakage系数,需要进行调参。此外,对于某些问题,LeakyReLU函数并不一定比ReLU函数表现更好,具体需要根据实际情况进行选择。🐳
💥💥3.6 Softmax
Softmax函数是用于多类分类问题的激活函数,在多类分类问题中,超过两个类标签则需要类成员关系。对于长度为K 的任意实向量,Softmax函数可以将其压缩为长度为K ,值在(0,1)范围内,并且向量中元素的总和为1的实向量。
Softmax函数与正常的max函数不同:max函数仅输出最大值,但Softmax函数确保较小的值具有较小的概率,并且不会直接丢弃。我们可以认为它是arg max函数的概率版本或“soft”版本。Softmax函数的分母结合了原始输出值的所有因子,这意味着Softmax函数获得的各种概率彼此相关。
它的公式为:
m = nn.Softmax(dim=1)
input = torch.randn(2, 3)
output = m(input)
Softmax激活函数的特点:
(1)在零点不可微。
(2)负输入的梯度为零,这意味着对于该区域的激活,权重不会在反向传播期间更新,因此会产生永不激活的死亡神经元。
💥💥3.7 SiLU
SiLU(Sigmoid Linear Unit)激活函数是近年来提出的一种新型激活函数,它将Sigmoid函数和ReLU函数结合起来,具有一定的优势。
它的公式为:
m = nn.SiLU()
input = torch.randn(2)
output = m(input)
与ReLU函数相比,SiLU函数的导数更加平滑,没有ReLU函数的导数不连续问题。这种平滑性有助于防止在训练过程中出现梯度消失或者梯度爆炸的问题,从而提高模型的稳定性和收敛速度。
与Sigmoid函数相比,SiLU函数的导数在输入值较大时更接近于ReLU函数,可以避免Sigmoid函数的饱和性问题。同时,SiLU函数的值域也与ReLU函数相同,在输入值较大时,其输出值接近于输入值,可以避免神经元输出饱和的问题。
因此,SiLU激活函数在一些深度学习任务中表现良好,特别是在自然语言处理(NLP)领域中,SiLU激活函数有时能够比ReLU和Tanh函数获得更好的性能。🐳
🚀4.激活函数性质
☘️(1)非线性:当激活函数是非线性的,一个两层的神经网络就可以基本上逼近所有的函数。但如果激活函数是恒等激活函数的时候,即f(x)=x,就不满足这个性质,而且如果MLP使用的是恒等激活函数,那么其实整个网络跟单层神经网络是等价的。
☘️(2)可微性:可微性保证了在优化中梯度的可计算性。传统的激活函数如Sigmoid等满足处处可微。对于分段线性函数比如ReLU,只满足几乎处处可微(即仅在有限个点处不可微)。对于SGD算法来说,由于几乎不可能收敛到梯度接近于0的位置,有限的不可微点对于优化结果不会有很大影响。
☘️(3)计算简单:非线性函数有很多。激活函数在神经网络前向的计算次数与神经元的个数成正比,因此简单的非线性函数自燃更适合用作激活函数。这也是ReLU比其它使用Exp等操作的激活函数更受欢迎的其中一个原因。
☘️(4)非饱和性:饱和指的是在某些区间梯度接近于0(即梯度消失),使得参数无法继续更新的问题。最经典的例子是Sigmoid,它的导数在x为比较大的正值和比较小的负值时都会接近于0。更极端的例子是阶跃函数,由于它在几乎所有位置的梯度都为0,因此处处饱和,无法作为激活函数。ReLU在x>0时导数恒为1,因此对于更大的正值也不会饱和,但同时对于x<0,其梯度恒为0,这时候它也会出现饱和的现象。LeakyReLU的提出正是为了解决这一问题。
☘️(5)单调性:即导数符号不变。当激活函数是单调的时候,单层网络能够保证是凸函数。
☘️(6)输出范围有限:有限的输出范围使得网络对于一些比较大的输入也会比较稳定,这也是为什么早期的激活函数都以此类函数为主的原因,如Sigmoid、Tanh。但这导致了前面提到的梯度消失问题,而且强行让每一层的输出限制在固定范围内会限制其表达能力,因此现在这类函数仅用于某些需要特定输出范围的场合,比如概率输出(此时loss函数中的log操作能够梯度消失的影响)、LSTM里的gate函数。
☘️(7)接近恒等变换:f(x)≈x,即约等于x。这样的好处是使得输出的幅值不会随着深度的增加而发生显著的增加,从而使网络更加稳定,同时梯度也能够更容易地回传。这个与非线性是有点矛盾的,因此激活函数基本上只是部分满足这个条件。
☘️(8)参数少:大部分激活函数都是没有参数的。
☘️(9)归一化:对应的激活函数是SELU,主要思想是使样本分布自动归一化到零均值、单位方差的分布,从而稳定训练。归一化的思想也被用于网络结构的设计,比如Batch Normalization。
🚀5.如何选择激活函数
目前激活函数非常的多,选择一个最适合的激活函数并不容易,需要考虑很多因素,通常的做法是,如果不确定哪一个激活函数效果更好,可以把它们都试一下,然后在验证集或者测试集上进行评价,然后看哪一种表现的更好,就去使用它。在实际应用过程中通常可以考虑目前使用最广泛的,比如ReLU、SiLU等。🌴
以下是常见的选择情况:
☘️(1)如果输出是0、1值(二分类问题),则输出层选择Sigmoid函数,然后其它的所有单元都选择ReLU函数。
☘️(2)如果在隐藏层上不确定使用哪个激活函数,那么通常会使用ReLU激活函数。有时,也会使用Tanh激活函数,但ReLU的一个优点是:当是负值的时候,导数等于0。
☘️(3)Sigmoid激活函数:除了输出层是一个二分类问题,基本不会使用它。
☘️(4)Tanh激活函数:Tanh是非常优秀的,几乎适合所有场合。
☘️(5)ReLU激活函数:最常用的默认函数,如果不确定用哪一个激活函数,就使用ReLU或者LeakyReLU,再去尝试其他的激活函数。
☘️(6)如果遇到一些死的神经元,我们可以使用LeakyReLU函数。