文章目录
- 1. Swish
- 基本定义
- 主要特点
- 代码实现
- 2. GLU (Gated Linear Unit)
- 基本定义
- 主要特点
- 代码实现
- 3. SwiGLU
- 基本定义
- 主要特点
- 代码实现
- 参考资料
SWiGLU是大模型常用的激活函数,是2020年谷歌提出的激活函数,它结合了Swish和GLU两者的特点。SwiGLU激活函数因其在多个方面的优势而被广泛应用于大型语言模型中。
1. Swish
基本定义
Swish是由Google Brain提出的一种激活函数,它的数学表达式如下:
其中 σ ( x ) \sigma(x) σ(x) 是sigmoid函数,β是一个可学习的参数。
- 当β趋近于0时,Swish函数趋近于线性函数 y = x 2 y = x^2 y=x2
- 当β取值为1时,Swish函数是光滑且非单调的,等价于SiLU激活函数
- 当β趋近于无穷大时,Swish函数趋近于ReLU函数。
Swish函数的图如下所示:
Swish的名称可能来源于其形状与鱼的尾巴相似,给人一种平滑、流畅的联想,这与"swish"这个词的含义相吻合。
补充:SiLU(Sigmoid Linear Unit)激活函数表达式如下:
SiLU具备无上界有下界、平滑、非单调的特性。SiLU在深层模型上的效果优于 ReLU。可以看做是平滑的ReLU激活函数。
主要特点
Swish函数的特点包括:
- 非线性:Swish引入了非线性,使得神经网络能够学习和模拟复杂的函数。
- 平滑性:Swish函数在整个定义域内都是光滑且连续的,这有助于在优化过程中计算梯度。
- 自适应性:Swish函数的输出取决于输入值,这使得它能够自适应地调整激活函数的形状。
Swish函数在一些实验中表现出了比ReLU更好的性能,尤其是在一些深度神经网络中。Swish函数既有 ReLU(Rectified Linear Unit)激活函数的一些优点(例如,能够缓解梯度消失问题),又能解决 ReLU 函数的一些缺点(例如,ReLU 函数不是零中心的,且在负数部分的梯度为零)。此外,Swish 函数还是平滑函数,这意味着它在整个定义域内都有导数,这有利于优化。然而,Swish函数的计算复杂度较高,因为它涉及到sigmoid函数的计算。因此,在实际应用中,需要根据具体的任务和模型结构来选择合适的激活函数。
代码实现
Swish函数的代码实现如下:
import numpy as np
def swish(x,beta=1.0):
"""Swish 激活函数
参数:
x -- 输入值
返回:
Swish 激活后的值
"""
return x * sigmoid(beta*x)
def sigmoid(x):
"""Sigmoid 函数
参数:
x -- 输入值
返回:
Sigmoid 函数的输出值
"""
return 1 / (1 + np.exp(-x))
2. GLU (Gated Linear Unit)
基本定义
GLU (Gated Linear Unit) 其实不算是一种激活函数,而是一种神经网络层。它是一个线性变换后面接门控机制的结构。其中门控机制是一个sigmoid函数用来控制信息能够通过多少。GLU结合了线性单元和门控机制,能够有效地学习输入数据的不同特征。
笔者在之前的博客中也介绍过在语言模型的建模方面GLU与RNN相比的差异,具体可以参考:GLU(Gated Linear Unit) 门控线性单元
GLU的数学表达式如下:
其中 ⊗ 表示逐元素乘法, X X X 是输入, W W W 和 V V V 是权重矩阵, b b b 和 c c c 是偏置项。
主要特点
GLU的特点包括:
- 门控机制:GLU引入了门控机制,通过sigmoid函数控制输入的线性变换,从而使得神经网络能够学习输入数据的不同特征。
- 非线性:GLU引入了非线性,使得神经网络能够学习和模拟复杂的函数。
- 自适应性:GLU函数的输出取决于输入值,这使得它能够自适应地调整激活函数的形状。
代码实现
GLU函数的代码实现如下:
import numpy as np
def glu(x):
"""GLU 激活函数
参数:
x -- 输入数组,维度必须是偶数
返回:
GLU 激活后的数组
"""
assert x.shape[-1] % 2 == 0, "输入数组的最后一个维度必须是偶数"
half_dim = x.shape[-1] // 2
return x[..., :half_dim] * sigmoid(x[..., half_dim:])
def sigmoid(x):
"""Sigmoid 函数
参数:
x -- 输入值
返回:
Sigmoid 函数的输出值
"""
return 1 / (1 + np.exp(-x))
3. SwiGLU
基本定义
终于到了我们今天的主角-SwiGLU。SwiGLU是一种结合了Swish和GLU的激活函数,它结合了Swish的平滑性和GLU的门控机制,能够有效地学习输入数据的不同特征。
SwiGLU的数学表达式如下:
主要特点
SwiGLU激活结合了Swish和GLU的特点,提供了一种有效的激活机制,具体来说:
- 非线性能力:SwiGLU通过Swish激活函数引入非线性,这使得模型能够学习和表示更复杂的数据模式 。
- 门控特性:GLU的门控机制允许模型动态地调整信息流,使得模型在处理长序列数据时能够更好地捕捉长距离依赖关系 。
- 梯度稳定性:SwiGLU在负输入区域提供非零的梯度,有助于缓解梯度消失问题,从而提高模型的训练稳定性 。
- 可学习参数:SwiGLU的参数可以通过训练学习,使得模型可以根据不同任务和数据集动态调整,增强了模型的灵活性和适应性 。
- 计算效率:相比于一些复杂的激活函数,SwiGLU在保持性能的同时,具有较高的计算效率,这对于大规模语言模型的训练和推理尤为重要 。
由于这些优势,SwiGLU在大型语言模型如LLAMA、OLMO和PALM中得到了应用 。它通过结合Swish的平滑性和GLU的门控机制,提供了一种有效的激活函数,以支持复杂和高效的深度学习模型训练 。
代码实现
SwishGLU函数的代码实现如下:
import numpy as np
def SwiGLU(x):
"""SwiGLU 激活函数
参数:
x -- 输入数组,维度必须是偶数
返回:
SwiGLU 激活后的数组
"""
assert x.shape[-1] % 2 == 0, "输入数组的最后一个维度必须是偶数"
half_dim = x.shape[-1] // 2
return x[..., :half_dim] * swish(x[..., half_dim:])
def swish(x,beta=1.0):
"""Swish 激活函数
参数:
x -- 输入值
返回:
Swish 激活后的值
"""
return x * sigmoid(beta*x)
def sigmoid(x):
"""Sigmoid 函数
参数:
x -- 输入值
返回:
Sigmoid 函数的输出值
"""
return 1 / (1 + np.exp(-x))
参考资料
- 【笔记】SWiGLU激活函数-大模型常用
- LLMForEverybody / 为什么大型语言模型都在使用SwiGLU作为激活函数?