激活函数在神经网络中起着非常重要的作用,它能够引入非线性特性,增强模型的表达能力,解决梯度消失问题,以及引入稀疏性和稳定性,从而提高神经网络的性能和效果。
这个世界很多规律无法用线性模型表达,比如XOR问题等,你无法用一条直线来解决,所以需要非线形的模型来做这类事。
这里总结一下遇到的常用的那些激活函数。
Sigmoid 的输出是在0到1之间,可以作为二分类算法的输出分类概率使用,同时它单调可导。
但是它的局限性也很明显:
在torch中表达如下:
import torch
import torch.nn as nn
# init layer
activation_layer = nn.Sigmoid()
# input
x = torch.rand(2, 10)
print(x)
# apply activation
x = activation_layer(x)
print(x)
双曲正切曲线。它的区间为 -1 到 1,并且以 0 为中心。虽然 tanh 函数具有零中心和更广的输出范围等优点,但在深层神经网络中仍然存在一些局限性,如梯度消失、梯度爆炸、计算复杂度高等问题。
在torch中表达如下:
import torch
import torch.nn as nn
activation_layer = nn.Tanh()
x = torch.rand(2, 10)
x = activation_layer(x)
ReLU 激活函数具有计算速度快、抑制梯度消失问题、稀疏激活性和线性特性等优点。这可能是我们最常用的激活函数了,但它也存在 Dead ReLU 问题和不以零为中心的缺点。
Dead ReLU 问题:当神经元的输入小于等于零时,ReLU 激活函数输出为零,这可能会导致一些神经元永远无法被激活,称为“死亡神经元”(Dead Neurons)。这些神经元对于梯度更新不起作用,可能会影响网络的表达能力。
它的表达是好简单:f(x) = max(x, 0)
在torch中的表达如下:
import torch
import torch.nn as nn
activation_layer = nn.ReLU()
x = torch.rand(2, 10)
x = activation_layer(x)
为了解决Dead ReLU的问题产生。公式:f(x) = max(0.01x, x)
看公式表达就可以知道,它是通过给负数都乘上一个很小的数字解决的,这样就会避免了很多的死亡神经元。
在torch中的表达是nn.LeakyReLU(0.01)
。
公式:f(x) = max(ax, x)。
Parametric ReLU(PReLU)是一种改进的 ReLU 激活函数,与标准的 ReLU 不同之处在于,PReLU 具有一个可学习的参数,即它允许神经网络自动学习激活函数的形状,而不是像 ReLU 那样硬编码为 0 或者线性。
其中,a 是一个可学习的参数,可以通过反向传播算法来优化。如果 a 被学习到的值接近于 0,则 PReLU 的行为类似于 ReLU;如果 a 被学习到的值大于 0,则 PReLU 的行为类似于 Leaky ReLU,即允许小于零的部分有一个小的斜率。
PReLU 的优点包括:
然而,PReLU 也存在一些缺点:
在torch中的表达是nn.PReLU()
。
softmax大软熊主要在多分类问题的最后一个layer中出现。在torch中的表达如下:nn.Softmax(dim=-1)
。它所输出的值的综合为1,并增强对最大值的响应。
在训练过程中,Softmax 函数常与交叉熵损失函数(Cross-Entropy Loss)结合使用,用于衡量模型预测值与真实标签之间的差异,并通过反向传播算法进行模型参数的优化。
以下是各种激活函数适用的常见算法总结:
import torch
seed = 172
torch.manual_seed(seed)
def m_sigmoid(x):
return 1 / (1 + torch.exp(-x))
def m_tanh(x):
return (torch.exp(x) - torch.exp(-x)) / (torch.exp(x) + torch.exp(-x))
def m_relu(x):
return torch.mul(x, (x > 0))
return torch.max(torch.tensor(0, dtype=x.dtype), x)
# 这两种写法都可以,但是可以看到第一种更短,第二种看到如果不加数据类型会报错
def m_softmax(x):
return torch.exp(x) / torch.sum(torch.exp(x))