三个激活函数模块:GELU
、SELU
和 RELU
。这些模块的实现都遵循类似的结构,并通过 forward
方法实现它们的计算逻辑。下面逐步分析每个模块的实现和作用。
1. GELU
(Gaussian Error Linear Unit)
class GELU(nn.Module):
def forward(self, x):
x, gates = x.chunk(2, dim = -1)
return x * F.gelu(gates)
GELU
是一种常见的激活函数,通常用于深度神经网络中,尤其是在一些Transformer模型(如BERT)中被广泛使用。GELU 是基于高斯分布的激活函数,具有平滑的非线性特性。x.chunk(2, dim=-1)
:- 这里,
x.chunk(2, dim=-1)
将输入x
沿着最后一个维度(即特征维度)拆分成两个部分:x
和gates
。dim=-1
指的是对最后一个维度进行拆分,拆分成两个相等的部分。 x
和gates
的形状将是原始输入的一半。假设输入x
的形状为[batch_size, features]
,则x
和gates
的形状将是[batch_size, features // 2]
。
- 这里,
F.gelu(gates)
:F.gelu(gates)
应用的是 GELU 激活函数。GELU 函数的公式是:
GELU ( z ) ≈ 0.5 ⋅ z ( 1 + tanh ( 2 π ( z + 0.044715 z 3 ) ) ) \text{GELU}(z) \approx 0.5 \cdot z \left( 1 + \tanh \left( \sqrt{\frac{2}{\pi}} \left( z + 0.044715 z^3 \right) \right) \right) GELU(z)≈0.5⋅z(1+tanh(π2(z+0.044715z3)))
它通常用于替代 ReLU 激活函数,具有更平滑的曲线和更好的表现。
return x * F.gelu(gates)
:- 最终输出是将
x
和F.gelu(gates)
的结果逐元素相乘。这种操作是对输入特征的一个加权处理,其中gates
控制了输入特征的激活程度。x
和gates
被拆分后,通过gates
激活函数产生的值来“调制”x
的值。
- 最终输出是将
2. SELU
(Scaled Exponential Linear Unit)
selu源于论文Self-Normalizing Neural Networks作者为 Sepp Hochreiter。
selu其实就是ELU乘lambda,论文中给出了lambda和alpha的值
lambda = 1.0507
alpha = 1.67326
class SELU(nn.Module):
def forward(self, x):
x, gates = x.chunk(2, dim = -1)
return x * F.selu(gates)
SELU
是一种自归一化激活函数,它是基于 ELU(Exponential Linear Unit)提出的。SELU 激活函数具有特别的性质,在某些情况下能够自动归一化神经网络的输出,从而加速训练并提高模型的性能。x.chunk(2, dim=-1)
:- 与
GELU
模块相似,x.chunk(2, dim=-1)
将输入x
沿着最后一个维度拆分成两部分:x
和gates
。
- 与
F.selu(gates)
:F.selu(gates)
应用的是 SELU 激活函数。SELU 函数的定义如下:
SELU ( x ) = λ ( { x if x > 0 α ( e x − 1 ) if x ≤ 0 ) \text{SELU}(x) = \lambda \left( \begin{cases} x & \text{if } x > 0 \\ \alpha (e^x - 1) & \text{if } x \leq 0 \end{cases} \right) SELU(x)=λ({xα(ex−1)if x>0if x≤0)
其中,λ
和α
是常数,通常选择λ = 1.0507
和α = 1.6733
。SELU 具有自归一化的性质,能够在某些条件下让神经网络的激活值保持均值为零,方差为 1,从而有助于加速训练过程。
return x * F.selu(gates)
:- 通过
gates
的 SELU 激活函数输出对x
进行加权,类似于GELU
中的加权过程。
- 通过
3. RELU
(Rectified Linear Unit)
class RELU(nn.Module):
def forward(self, x):
x, gates = x.chunk(2, dim = -1)
return x * F.relu(gates)
RELU
是一种广泛使用的激活函数,它将所有负值置为零,保留正值。RELU 具有简单且高效的计算特性,能够有效缓解梯度消失问题。x.chunk(2, dim=-1)
:- 和前面的模块一样,
x.chunk(2, dim=-1)
将输入x
沿着最后一个维度拆分成两个部分:x
和gates
。
- 和前面的模块一样,
F.relu(gates)
:F.relu(gates)
对gates
应用 ReLU 激活函数,ReLU 的计算公式是:
ReLU ( x ) = max ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x)
这将把所有负值置为零,保留正值。
return x * F.relu(gates)
:- 最终输出是将
x
和F.relu(gates)
的结果逐元素相乘。这意味着gates
经过 ReLU 激活后,会根据gates
的激活程度来调整x
的值。
- 最终输出是将
总结
这三个类都定义了自定义的激活函数,它们有以下共同特点:
-
输入拆分:每个类的
forward
方法都通过x.chunk(2, dim=-1)
将输入x
沿着最后一个维度拆分成两部分,x
和gates
。然后使用gates
部分经过激活函数的处理,最终通过逐元素相乘的方式与x
结合。 -
不同的激活函数:
GELU
使用高斯误差线性单元(Gaussian Error Linear Unit)。SELU
使用自归一化的指数线性单元(Scaled Exponential Linear Unit)。RELU
使用常见的修正线性单元(Rectified Linear Unit)。
-
逐元素乘法:这些激活函数通过将
x
和激活后的gates
部分逐元素相乘来进行加权。
使用场景
这种设计的一个潜在目的可能是让模型在不同的“门”(gates
)控制下根据不同的激活函数对 x
进行加权操作。这种设计可能在某些应用场景中会有所帮助,尤其是在复杂的神经网络模型中,可以通过不同类型的激活函数来灵活控制特征的激活方式。
这种结构不太常见,通常可以用于实验性模型或者模型中需要灵活切换不同类型激活函数的情况。