1、sigmoid函数
torch.nn.sigmoid()
公式:
是早期发展使用频率最高的函数,将输出平滑的映射到0~1,是便于求导的平滑函数。
缺点:
(1)在深度神经网络中梯度反向传递时导致梯度爆炸和梯度消失,其中梯度爆炸发生的概率非常小,而梯度消失发生的概率比较大。
(2)随着网络层数的增加,由于链式法则,连乘的sigmoid函数导数会变得越来越小,导致梯度难以回转,这会降低网络的收敛速率,甚至导致网络不能收敛到好妆态。
2、Tanh函数
torch.nn.Tanh()
Tanh函数解决了sigmoid函数的输出值并不以0为中心的问题,但是梯度消失的问题仍然存在。
公式:
3、线性ReLU函数
torch.nn.ReLU()
公式:
ReLU函数其实就是一个取最大值函数,注意这并不是全区间可导的,但是我们可以取sub-gradient,如上图所示。ReLU虽然简单,但却是近几年的重要成果,有以下几大优点:
1) 解决了gradient vanishing问题 (在正区间)
2)计算速度非常快,只需要判断输入是否大于0
3)收敛速度远快于sigmoid和tanh
ReLU也有几个需要特别注意的问题:
1)ReLU的输出不是zero-centered
2)Dead ReLU Problem,指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见 (2) learning rate太高导致在训练过程中参数更新太大,不幸使网络进入这种状态。解决方法是可以采用Xavier初始化方法,以及避免将learning rate设置太大或使用adagrad等自动调节learning rate的算法。
尽管存在这两个问题,ReLU目前仍是最常用的activation function,在搭建人工神经网络的时候推荐优先尝试!
原文链接:
4、线性ReLU函数的改进-Leaky ReLU
torch.nn.Leaky ReLU()
公式:
f(x)=max{0.01x,x}
Leaky ReLU函数的提出解决了,ReLU函数中出现的Dead ReLU问题。
5、线性ReLU函数的改进- ELU
torch.nn.ELU()
公式:
ELU函数是针对ReLU函数的一个改进型,相比于ReLU函数,在输入为负数的情况下,是有一定的输出的,而且这部分输出还具有一定的抗干扰能力。这样可以消除ReLU死掉的问题,不过还是有梯度饱和和指数运算的问题。其对噪声具有较高的鲁棒性,但是由于需要计算指数,计算量比较大。
SELU(x)=
*ELU(x)
6、线性ReLU函数的改进- PreLU
torch.nn.PReLU()
将LeakyReLU中的0.01设置为可以学习的参数
,就得到了PreLU函数。
公式:
PReLU也是针对ReLU的一个改进型,在负数区域内,PReLU有一个很小的斜率,这样也可以避免ReLU死掉的问题。相比于ELU,PReLU在负数区域内是线性运算,斜率虽然小,但是不会趋于0,这算是一定的优势吧。
pytorch中的例子:
>>> import torch
>>> import torch.nn as nn
>>> m = nn.RReLU(0.1, 0.3)
>>> input = torch.randn(2)
>>> output = m(input)
>>> output
tensor([-0.0875, -0.2063])
7、Maxout函数
maxout函数就是最大值函数,它从多个输入中取最大值。可以看作在深度学习网络中加入一层激活函数层,包含一个参数k,相当于增加了k个神经元,并输出最大的激活值。
pytorch代码实现:
from torch.nn import init
import torch.nn.functional as F
from torch._jit_internal import weak_module, weak_script_method
from torch.nn.parameter import Parameter
import math
@weak_module
class Maxout(nn.Module):
__constants__ = ['bias']
def __init__(self, in_features, out_features, pieces, bias=True):
super(Maxout, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.pieces = pieces
self.weight = Parameter(torch.Tensor(pieces, out_features, in_features))
if bias:
self.bias = Parameter(torch.Tensor(pieces, out_features))
else:
self.register_parameter('bias', None)
self.reset_parameters()
def reset_parameters(self):
init.kaiming_uniform_(self.weight, a=math.sqrt(5))
if self.bias is not None:
fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
bound = 1 / math.sqrt(fan_in)
init.uniform_(self.bias, -bound, bound)
@weak_script_method
def forward(self, input):
output = input.matmul(self.weight.permute(0, 2, 1)).permute((1, 0, 2)) + self.bias
output = torch.max(output, dim=1)[0]
return output
#调用
#就是跟nn.Linear一样的用。pieces的概念,就是pieces个函数,
#在定义上每个点上,取最大的那个函数对应的数值,作为整个函数的最大值。
nn.Sequential(
Maxout(in_c, out_c, pieces)
)
Maxout函数的拟合能力非常强,可以拟合任意凸函数,具有ReLU函数所有的优点,线性、不饱和性,同时没有ReLU函数的缺点。实验表明Maxout函数与Dropout组合使用可以发挥比较好的效果。
8、激活函数的自动搜索-Swish函数
Swish函数先对来说是比较新的一些激活函数,算是由之前的激活函数复合而成出来的,Swish函数的表达式是f ( x ) = x ⋅ σ ( x ) f(x)=x·\sigma(x)f(x)=x⋅σ(x),σ ( x ) \sigma(x)σ(x)就是sigmoid函数。因为sigmoid函数的饱和性容易导致梯度消失,借鉴ReLU的效果,当x xx非常大的时候,这个时候有f ( x ) f(x)f(x)趋近于x xx,但是当x → − ∞ , 则 f ( x ) → 0 x→-∞,则f(x)→0x→−∞,则f(x)→0,函数的大致走势和ReLU比较相似,但是又比ReLU复杂。
激活函数的研究方向:
1、对ReLU函数的负区域进行改进
2、研究不同激活策略对不同的网络层、不同的通道使用的影响。
3、使用各类学习方法来对简单函数的组合进行探索。