深度学习——激活函数、损失函数、优化器、参数显存占用分析
1、激活函数
激活函数将非线性引入到网络中,没有激活函数相当于原始的感知机,只有线性操作,近似为矩阵相乘操作,加入激活函数后可以更好地拟合非线性函数。
1.1、一些常见的激活函数
1.1.1、sigmoid
σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1+e^{-x}} σ(x)=1+e−x1
特点:将负无穷到正无穷的输入映射到0-1,处处连续可导,可以用于二分类,导数为 σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) ) \sigma'(x)=\sigma(x)(1-\sigma(x)) σ′(x)=σ(x)(1−σ(x))
缺点:在输出值接近0或1时会出现饱和现象,在反向传播时梯度较小,容易梯度消失,从而无法完成深层网络的训练。输出不是0均值的,会导致后层的神经元的输入是非0均值的信号,这会对梯度产生影响。并且计算复杂度较高,因为涉及到指数。
1.1.2、softmax
S o f t m a x ( x i ) = e x i Σ j e x j Softmax(x_i)=\frac{e^{x_i}}{\Sigma_j{e^{x_j}}} Softmax(xi)=Σjexjexi
softmax可以将上一层的原始数据进行归一化,转化为一个(0,1)之间的数值,这些数值可以被当作概率分布,用来作为多分类的目标预测值,一般作为神经网络的最后一层,接收上一层网络的输入值,然后将其转化为概率。sigmoid是softmax的一个特例,sigmoid函数只能用于预测值为0或1的二元分类。
1.1.3、tanh
σ ( x ) = e x − e − x e x + e − x \sigma(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}} σ(x)=ex+e−xex−e−x
输出范围在-1~1,相比sigmoid函数,是0均值,会比sigmoid函数要好一些,但是仍然会存在容易梯度消失的问题。并且计算复杂度仍然较高。
1.1.4、ReLU
σ ( x ) = { 0 x < 0 x x ⩾ 0 \sigma(x) = \begin{cases} 0 & x<0 \\ x & x \geqslant 0 \end{cases} σ(x)={
0xx<0x⩾0
或者 σ ( x ) = m a x ( 0 , x ) \sigma(x) = max(0,x) σ(x)=max(0,x)
整流线性单元,使用ReLU的SGD算法收敛速度比sigmoid和tanh快,在x>0时不会出现梯度消失问题,在x<0时,梯度为0,无法传播到前一层。计算复杂度低。
缺点:输出不是0均值的,并且在x<0时会存在神经元坏死问题,梯度无法传播,其后面的神经元梯度都为0,无法更新参数。
1.1.5、Leaky ReLU
σ ( x ) = { α x x < 0 x x > 0 \sigma(x) = \begin{cases} \alpha x & x<0 \\ x & x>0 \\ \end{cases} σ(x)={
αxxx<0x>0
alpha默认0.01;为解决ReLU神经元坏死的问题,引入了LeakReLU,使得激活函数在负数区域也存在微小的梯度,而梯度是固定的斜率。
1.1.6、PReLU
σ ( x ) = { a x x < 0 x x > 0 \sigma(x) = \begin{cases} ax & x<0 \\ x & x>0 \\ \end{cases} σ(x)={
axxx<0x>0
和LeakReLU不同的是这里的参数 a a a是可学习的
1.1.7、GeLU
σ ( x ) = 1 1 + e − 1.702 x \sigma(x) = \frac{1}{1+e^{-1.702x}} σ(x)=1+e−1.702x1
在Transformer里面用的多一些
1.1.8、ELU
σ ( x ) = { α ( e x − 1 ) x < 0 x x > 0 \sigma(x) = \begin{cases} \alpha(e^x-1) & x<0 \\ x & x>0 \\ \end{cases} σ(x)={
α(ex−1)xx<0x>0
有负数饱和区域,从而对噪声有一些鲁棒性。可以看做是介于ReLU和Leaky ReLU之间的一个函数。当然,这个函数也需要计算exp,从而计算量上更大一些。
1.1.9、Swish
f ( x ) = x ⋅ σ ( β ⋅ x ) f(x) = x \cdot \sigma(\beta \cdot x) f(x)=x⋅σ(β⋅x)
其中 σ \sigma σ是Sigmoid激活函数。 σ ( x ) = 1 1 + e − x \sigma(x)=\frac{1}{1+e^{-x}} σ(x)=1+e−x1,
特点:和ReLU一样没有上边界,因此不会出现梯度饱和的现象;有下边界,可以产生更强的正则化效果(x左半轴慢慢趋近于0),非单调,处处连续可导,更容易训练。
1.1.10、GLU
GLU(Gated Linear Units)其实不算是一种激活函数,而是一种神经网络层,是一个线性变换后面接门控机制的结构。门控机制是一个sigmoid函数用来控制信息能够通过多少。
G L U ( x , W , V , b , c ) = σ ( x W + b ) ⊗ ( x V + c ) GLU(x, W, V, b, c)=\sigma(xW+b) \otimes (xV+c) GLU(x,W,V,b,c)=σ(xW+b)⊗(xV+c)
其中 σ \sigma σ是Sigmoid激活函数, ⊗ \otimes ⊗是逐元素乘法,通过使用其他激活函数,就可以得到各种GLU的变体。
1.1.11、SwiGLU
采用Swish作为激活函数的GLU变体。
S w i G L U ( x , W , V , b , c ) = S w i s h ( x W + b ) ⊗ ( x V + c ) SwiGLU(x, W, V, b, c)=Swish(xW+b) \otimes (xV+c) SwiGLU(x,W,V,b,c)=Swish(xW+b)⊗(xV+c)
1.2、激活函数的特点
1.2.1、非线性
即导数不能是常数,来保证多层网络不退化成单层线性网络
1.2.2、几乎处处可微
几乎处处可微保证了在优化中梯度的可计算性,ReLU仅在有限个点处不可微。有限个不可微的点对优化结果不会有很大的影响。
1.2.3、计算简单
因为每一个神经元的输出都需要经过激活函数,简单的函数像是ReLU更适合做激活函数。
1.2.4、非饱和性
Sigmoid在正负区域都有饱和区,ReLU在负半轴有饱和区,饱和区参数无法得到有效更新,leakyReLU就是为了解决这个问题。
1.2.5、单调性、输出范围有限
2、损失函数
2.1、深度估计回归损失
2.1.1、L1损失函数
L1损失函数:最小绝对值偏差、最小绝对值误差:是目标值与估计值的绝对差值的总和。缺点:不稳定。收敛速度慢。优点:对离群点异常值更具有鲁棒性。
L 1 ( y ^ − y ) = ∑ i = 0 m ∣ y ( i ) − y ^ ( i ) ∣ L_1(\hat{y}-y)=\sum_{i=0}^m\left|y^{(i)}-\hat{y}^{(i)}\right| L1(y^−y)=i=0∑m
y(i)−y^(i)
torch.nn.L1Loss(size_average=None, reduce=None, reduction='sum') # size_average与reduce已经被弃用,具体功能可由reduction替代。
l1_loss = torch.nn.L1Loss(size_average=None, reduce=None, reduction='sum') # 创建实例
loss = l1_loss(src,tgt)
L 1 ( y ^ − y ) = 1 N ∑ i = 0 m ∣ y ( i ) − y ^ ( i ) ∣ L_1\left(\hat{y}-y\right)=\frac1N\sum_{i=0}^m\left|y^{(i)}-\hat{y}^{(i)}\right| L1(y^−y)=N1i=0∑m
y(i)−y^(i)
torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
,相当于MAE平均绝对误差。
torch.nn.functional.l1_loss(src, tgt, reduction='mean')
torch.mean(torch.abs(src-tgt))
(src-tgt).abs().mean()
如果是np.ndarray的话
np.mean(np.abs(src-tgt))
np.ndarray没有.abs()方法,只有类np.abs()函数
2.1.2、L2损失函数
L2损失函数:均方误差:是目标值与估计值的差值的平方和。缺点:对异常值更敏感。梯度更新方向容易受离群点主导。
L 2 ( y ^ , y ) = ∑ i = 0 m ( y ( i ) − y ^ ( i ) ) 2 L_2(\hat{y},y)=\sum_{i=0}^m(y^{(i)}-\hat{y}^{(i)})^2 L2(y^,y)=i=0∑m(y(i)−y^(i))2
torch.nn.MSELoss(size_average=None, reduce=None, reduction='sum')
torch.sum(torch.pow(src-tgt,2))
np.sum(np.power(src-tgt,2))
L 2 ( y ^ , y ) = 1 N ∑ i = 0 m ( y ( i ) − y ^ ( i ) ) 2 L_2(\hat{y},y)=\frac1N\sum_{i=0}^m(y^{(i)}-\hat{y}^{(i)})^2 L2(y^,y)=N1i=0∑m(y(i)−y^(i))2
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
,相当于MSE均方误差。
torch.mean(torch.pow(src-tgt,2))
np.mean(np.power(src-tgt,2))
2.1.3、smooth L1损失函数
smooth L1损失函数:平滑之后的L1损失函数:分段函数,来消除L1的折点不光滑问题。当误差的绝对值较小时采用MSE,当误差的绝对值较大时采用MAE。
S m o o t h L 1 = 0.5 x 2 , ∣ x ∣ < 1 ∣ x ∣ − 0.5 , x < − 1 或者 x > 1 SmoothL_1=\begin{aligned}