同学你好!本文章于2021年末编写,获得广泛的好评!
故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现,
Pytorch深度学习·理论篇(2023版)目录地址为:
CSDN独家 | 全网首发 | Pytorch深度学习·理论篇(2023版)目录
本专栏将通过系统的深度学习实例,从可解释性的角度对深度学习的原理进行讲解与分析,通过将深度学习知识与Pytorch的高效结合,帮助各位新入门的读者理解深度学习各个模板之间的关系,这些均是在Pytorch上实现的,可以有效的结合当前各位研究生的研究方向,设计人工智能的各个领域,是经过一年时间打磨的精品专栏!
https://v9999.blog.csdn.net/article/details/127587345
欢迎大家订阅(2023版)理论篇
以下为2021版原文~~~~
①激活函数:主要通过加入非线性因素,你不线性模型表达能力不足的缺陷,因为神经网络中的数学基础是处处可微分的函数,故要求激活函数也应该保证数据的输入与输出是可微分。
②激活函数可以分为饱和激活函数与不饱和激活函数,激活函数的右饱和指当x趋向于正无穷时,函数的导数趋近于0。同样的,当x趋向于负无穷时,函数的导数趋近于0,此时称为左饱和。当一个函数既满足右饱和,又满足左饱和,则称为饱和函数,否则称为非饱和函数。
1 Sigmoid函数
对于分类任务来说,如果仅仅给出分类的结果,在某些场景下,提供的信息可能并不充足,这就会带来一定的局限。因此,我们建立分类模型,不仅应该能够进行分类,同时,也应该能够提供样本属于该类别的概率。这在现实中是非常实用的。例如,某人患病的概率,明天下雨概率等。因此,我们需要将z的值转换为概率值,逻辑回归使用sigmoid函数来实现转换。
1.1 Sigmoid函数介绍
1.1.1 表达式
1.1.2 函数原型
1.1.3 图像
图像描述:在x趋近于正无穷与负无穷的情况下,函数值去想与1或者0,这种情况称为饱和。处于饱和状态的函数将意味着,x=10与x=1000在结果上无差别,使得在这个区间内的信息被丢弃。
1.1.4 LogSigmoid
函数表示为
图像表示为
LogSigmoid激活函数常常被用作与NULLoss损失函数一起使用,用作神经网络反向传播过程中的计算交叉熵的环节。
1.2 LogSigmoid()与Sigmoid()代码
import torch from torch import nn input = torch.autograd.Variable(torch.randn(2)) print(input) #输出 tensor([0.3439, 0.6682]) ### 函数括号后还有一个括号,介绍第一个函数返回了一个函数 ### 如果后面还有括号,介绍前面那个也返回了一个函数。以此类推。 print(nn.Sigmoid()(input)) # 输出 tensor([0.5851, 0.6611]) print(nn.LogSigmoid()(input)) # tensor([-0.5359, -0.4139])
2 tanh函数
2.1 函数介绍
tanh是Sigmoid值域的升级版,从0~1升为-1~1,但是不能完全代替,因为在需要输出结果始终大于0的情况下,还需要Sigmoid函数。
tanh函数依旧存在饱和问题,输入的绝对值不可过大,否则无法训练
2.1.1 函数图像
2.1.2 代码
torch.nn.tanh(input,out=None)
3 ReLU函数
3.1 函数介绍
3.1.1函数公式
3.1.2 函数图像
3.1.3 函数解释
当输入X大于0时,函数返回值为其本身。
当输入X小于0时,函数返回值为0
神经网络中使用ReLu函数可以取得很好的拟合效果,运算简单,效率高
3.2 ReLU的变种函数
3.2.1 ReLu6===》有效防止训练过程中的梯度爆炸现象
函数代码: relu6 = min(max(features, 0), 6)
特点:结果是把小于0的变成0,大于6的取6。
缺点:这个训练收敛比较快,但是收敛比较好后,目标检测网络回归框不太准。
import torch import torchvision import torch.nn as nn # inplace为True,将会改变输入的数据 ,否则不会改变原输入,只会产生新的输出 x = torch.linspace(-5, 10, 20) r6 = nn.ReLU6(inplace=True) print(x) y=r6(x) print(y) relu= nn.ReLU(inplace=True) y=relu(x) print(y) y2= torch.clamp(x,0,6) print(y2)
3.2.2 Leaky ReLU
Leaky ReLU函数的特点:
- Leaky ReLU函数通过把x xx的非常小的线性分量给予负输入0.01 x 0.01x0.01x来调整负值的零梯度问题。
- Leaky有助于扩大ReLU函数的范围,通常α \alphaα的值为0.01左右。
- Leaky ReLU的函数范围是负无穷到正无穷。
Leaky ReLU函数的图像:
3.2.3 PReLU
PReLU函数中,参数α \alphaα通常为0到1之间的数字,并且通常相对较小。
- 如果α i = 0 ,则PReLU(x)变为 ReLU。
- 如果α i > 0 ,则PReLU(x)变为Leaky ReLU。
- 如果α i是可学习的参数,则PReLU(x)为PReLU函数。
PReLU函数的特点:
- 在负值域,PReLU的斜率较小,这也可以避免Dead ReLU问题。
- 与ELU相比,PReLU 在负值域是线性运算。尽管斜率很小,但不会趋于0。
3.2.4 ELU
ELU有负值,这会使激活的平均值接近零。均值激活接近于零可以使学习更快,因为它们使梯度更接近自然梯度。
ELU函数的特点:
- 没有Dead ReLU问题,输出的平均值接近0,以0为中心。
- ELU 通过减少偏置偏移的影响,使正常梯度更接近于单位自然梯度,从而使均值向零加速学习。
- ELU函数在较小的输入下会饱和至负值,从而减少前向传播的变异和信息。
- ELU函数的计算强度更高。与Leaky ReLU类似,尽管理论上比ReLU要好,但目前在实践中没有充分的证据表明ELU总是比ReLU好。
ELU函数的图像:
3.3 ReLU对应的函数实现
- torch.nn.ReLU((input,inplace=False)是一般的ReLU函数,即max(input,,O)。如果参数inplace为Tue则会改变输入的数据,否则不会改变原输入,只会产生新的输出。
- torch.nn.ReLU6(input,,inplace:=False)是激活函数ReLU6的实现。如果参数inplace为True则将会改变输入的数据,否则不会改变原输入,只会产生新的输出。
- torch.nn.LeakyReLU(input,negative_slope=0.01,inplace=False)是激活函数LeakyReLU的实现。如果参数inplace为True则将会改变输入的数据,否则不会改变原输入,只会产生新的输出。
- torch.nn.PReLU(num_parameters-=1,init=0.25)是激活函数PReLU的实现。其中参数num_parameters代表可学习参数的个数,init代表可学习参数的初始值。
- torch.nn.ELU(alpha=1.0,inplace=False)是激活函数ELU的实现。
在使用ReLU搭建模型时,设置参数inplace为True还是False,只与内存的使用有关。
如果参数inplace为True,那么会减少内存的开销,但要注意的是,这时的输入值已经被改变了。
如果认为注意inplace增加了开发过程的复杂性,那么可以将ReLU的调用方式写成:
X=torch.nn.ReLU(X)
这种写法直接将函数torh.nn.ReLU()的返回值赋给一个新的x变量,而不再去关心原有输入X。即使torch.nn,ReLU()函数对输入的x做了修改,也不会影响程序的其他部分。
4 SoftPlus函数
4.1 函数介绍
4.1.1 函数公式
4.1.2 函数图像
4.1.3 函数解释
SoftPlus函数的曲线更平滑,计算量更大,对于小于0的值保留得更多
4.2 代码实现
torch.nn.Softplus(beta=1,threshold=20)
参数threshold为激活函数输出的最大阈
好的激活函数可以对特征数据的激活更加准确,使得提高模型的精度,其他结构不变的情况下,将激活函数变为Swish与Mish函数将使得模型的精度有所上升。
在大量实验结果表明,Mish>Swish
5 Swish(更好的激活函数)
5.1 Swish函数简介
5.1.1 Swish函数公式
PS:其中β为x的缩小参数,默认取1,但在使用批量归一算法的情况下,就需要对β进行调整。β可以手动调节,也可以由神经网络自动学习得到。
5.1.2 Swish函数图像
6 Mish(更好的激活函数)
6.1 Mish函数介绍
6.1.1 函数公式
Mish激活函数无边界(即正值可以达到任何高度)
6.1.2 函数图像
6.2 Swish与Mish函数的封装实现
import torch import torch.nn.functional as F import torch.nn as nn def swish(x,beta=1): # Swish激活函数 return x * torch.nn.Sigmoid()(x * beta) def mish(x): # Mish激活函数 return x * (torch.tanh(F.tanh(F.softplus(x)))) class Mish(nn.Module): #Mish激活函数的类方法实现 def __init__(self): super(Mish, self).__init__() def forward(self): return x * (torch.tanh(F.softplus(x)))
7 GELU(NLP任务的激活函数)
7.1 函数介绍 [ 高斯误差线性单元]
GELU函数就是一个综合体,它实现了非线性加上泛化,特别占内存,计算量很大
这里Φ ( x ) 是正太分布的概率函数,可以简单采用正太分布N ( 0 , 1 ) , 当然可以使用参数化的正太分布N ( μ , σ ) , 然后通过训练得到μ , σ 。
对于假设为标准正太分布的GELU(x),,论文中提供了近似计算的数学公式,如下:
7.1.1 GELE激活函数将激活参数0或1的取值概率与神经网络的激活值结合,使得神经网络具有自我确定性决策,即神经网络的激活值越小,其所乘的激活参数为1的概率越小
7.1.2 Swish与GELU函数的关系
Swish激活函数属于GELU的一个特例,Mish函数也属于GELU的一个特例。
7.2 代码实现
def gelu(input_tensor): cdf = 0.5 * (1.0 + tf.erf(input_tensor / tf.sqrt(2.0))) return input_tesnsor * cdf
8 激活函数总结
在神经网络中,特征见的差距会随着循环计算的推进而不断地被放大,当输入数据较大时,使用tanh()较为合理,输入数据差距较小时,使用Sigmoid()函数较为合适。
GeLU()激活函数,主要能够生成稀疏性更好的特征数据,即将数据转化为只有最大数值,其他为0 的特征,可以更好的突出输入特征,用大多数元素为0的稀疏矩阵来实现。
Swish与Mish函数是在ReLu基础上进一步优化产生,Mish()>Swish()