BLOG

Record, summarize, and improve.

Transformer:从注意力机制到高性能算子实现

工作步骤

在大规模机器学习模型中(特别是深度神经网络),输入向量和权重的计算以及权重的更新涉及到几个核心步骤,通常是在训练过程中使用梯度下降法(或其变种)来优化模型的参数。以下是详细的过程描述:

1. 输入向量与权重的计算:

在神经网络中,输入向量通常是由原始数据(如图像、文本、音频等)经过预处理和向量化后得到的。假设输入向量为 X (形状为 m×n,其中 m 是样本数量,n 是特征数量)。

神经网络的每一层都包含一个权重矩阵 W,它用于将输入向量转化为每一层的输出。假设输入层的权重矩阵为 W1,它的形状为 n×h(其中 h 是隐藏层的神经元数量)。则下一层的计算过程如下:

线性变换(加权和):Z=XW1+b1

其中 b1 是偏置项,Z 是加权后的输入,接下来通常会经过一个激活函数(如 ReLU、Sigmoid、Tanh 等)来进行非线性变换,生成该层的输出。

激活函数:A=f(Z)

其中 f 是激活函数,A 是该层的激活输出。

这些步骤在网络的每一层都会重复,直到最终的输出层。

2. 前向传播(Forward Propagation):

通过从输入层到输出层的这些线性变换和非线性变换,神经网络得到预测值 y^。

3. 损失函数(Loss Function):

在计算出预测值后,需要根据实际标签 y 计算损失(误差)。常用的损失函数包括:

  • 均方误差(MSE):用于回归任务。
  • 交叉熵损失:用于分类任务。

损失函数的形式通常为:

L=Loss(y,y^)

4. 反向传播(Backward Propagation):

反向传播算法是通过计算损失函数关于每个权重的梯度,来更新神经网络的参数(权重和偏置)。这通常是通过链式法则来完成的,目的是求出损失函数对每个权重的偏导数:

  • 梯度计算:

    对于每个权重 Wk,我们通过链式法则计算梯度:

    ∂L/∂Wk=∂L/∂Ak⋅∂Ak/∂Zk⋅∂Zk/∂Wk

    这里的每个部分代表从输出反向传播的误差信号,并通过链式法则逐层计算梯度。

其中:

  • ∂L/∂Ak 是损失对该层输出的梯度,
  • ∂Ak/∂Zk 是激活函数的导数,
  • ∂Zk/∂Wk 是该层加权输入对权重的梯度。
5. 权重更新(Weight Update):

使用计算出的梯度,神经网络会通过优化算法(如梯度下降或其变种)来更新权重。最常见的优化方法是 梯度下降(Gradient Descent),更新规则如下:

  • 标准梯度下降:

    Wk=Wk−η⋅∂L/∂Wk

    其中 η 是学习率,控制每次更新步长的大小。

  • 带动量的梯度下降(Momentum):通过引入前一步的更新值来加速收敛。
  • 自适应优化算法(如 Adam、Adagrad、RMSprop 等):这些优化算法根据梯度的历史和局部变化来动态调整学习率,通常能加速收敛并避免梯度消失或爆炸的问题。
6. 迭代更新:

这个过程会重复多次,通过不断的前向传播、反向传播和权重更新,神经网络的权重会逐步优化,从而最小化损失函数,最终实现对任务的较好性能。

总结:

  • 输入向量与权重的计算 是通过对输入向量进行加权和变换,经过激活函数生成输出。
  • 权重的更新 则是通过反向传播计算损失函数相对于每个权重的梯度,然后使用优化算法(如梯度下降)来调整权重。

这个过程反复进行,直到模型的性能收敛到一个较好的程度

Transformer核心工作层

Transformer模型的结构相对简单,但非常强大。除了最为人知的 自注意力层(Self-Attention)前馈神经网络层(Feed-Forward Network, FFN) 外,Transformer还有一些其他的层和机制,它们一起协同工作,使得模型能够有效地处理序列数据。

在典型的Transformer架构(如原始的Transformer模型,或基于其的变体,如BERT、GPT等)中,除了自注意力层和前馈层,主要还包括以下几个部分:

1. 输入嵌入层(Input Embedding Layer)
  • 作用:将输入序列(如词或子词)转化为稠密的向量表示。输入的每个词或子词都通过嵌入层映射到一个高维向量空间。
  • 功能:将离散的词(如词汇表中的每个词)表示为实值向量,并为每个词分配一个固定的维度。这样做可以将文本数据转化为模型可以理解的格式。
  • 实现方式:通常使用词嵌入矩阵 E∈RV×dmodel,其中 V 是词汇表的大小,dmodel 是嵌入向量的维度。
2. 位置编码层(Positional Encoding Layer)
  • 作用:Transformer模型是基于完全连接的注意力机制的,它本身没有序列的位置信息。因此,位置编码被添加到输入的嵌入表示中,以提供词在序列中的相对或绝对位置。
  • 功能:通过向嵌入向量添加位置编码来保持词的顺序信息。常见的做法是使用正弦和余弦函数生成位置编码。
  • 实现方式
    • 对于每个位置 p 和维度 i,位置编码是由正弦和余弦函数构造的:

      PE(p,2i)=sin(p/100002i/dmodel)

      PE(p,2i+1)=cos⁡(p/100002i/dmodel)

    • 位置编码是与词嵌入相加的。
3. 层归一化(Layer Normalization)
  • 作用:用于对每一层的输出进行归一化处理,从而稳定训练过程,加速收敛,减少梯度消失或爆炸的风险。
  • 位置:在 Transformer 中,层归一化通常出现在自注意力层和前馈神经网络层的输入和输出之间,通常在加上残差连接(Residual Connection)之后进行。
  • 实现方式

    LayerNorm(x)=(x−μ)/σ⋅γ+β

    其中 μ 和 σ 是输入的均值和标准差,γ 和 β 是可学习的参数。

4. 残差连接(Residual Connection)
  • 作用:帮助缓解深度网络中的梯度消失问题,并提高网络的训练效率。残差连接通过将输入直接加到输出中,允许梯度直接通过跳跃连接传播。
  • 位置:在自注意力层和前馈网络层之后,每一层都会使用残差连接。在每一层的输出上加入输入(经过适当的层归一化后),然后通过激活函数传递。
  • 实现方式

    output=LayerNorm(x+sub-layer output)

    其中 x 是输入,LayerNorm 是层归一化操作。

5. 输出层(Output Layer)
  • 作用:通常是模型的最后一层,用于生成最终的预测或输出。在序列生成任务中,输出层会生成预测的词或下一个时间步的结果。
  • 功能:在序列标注任务中(如命名实体识别、文本分类等),输出层通常是一个全连接层,用于映射每一位置的隐藏状态到标签空间;在序列生成任务中(如机器翻译、文本生成等),输出层通常通过 softmax 层输出概率分布,从而选择最可能的词。
  • 实现方式:通常使用一个线性层,将每个隐藏状态映射到目标空间的维度(例如,词汇表的大小),再经过 softmax 层输出。
6. 多头注意力机制(Multi-Head Attention)
  • 作用:将注意力机制扩展为多个头,以便模型能够从不同的角度捕捉输入序列中的不同关系。
  • 功能:每个注意力头对输入的不同部分进行加权,学习不同类型的表示。多头注意力机制将多个头的输出拼接起来,最后再通过一个线性变换得到最终的输出。
  • 实现方式

    MultiHead(Q,K,V)=Concat(head1,…,headh)WO

    其中每个头的计算是:

    headi=Attention(QWiQ,KWiK,VWiV)

    Q,K,V 分别是查询、键、值矩阵,WiQ,WiK,WiV 是每个头的权重矩阵。

7. 自注意力层(Self-Attention Layer)
  • 作用
    • 计算输入序列中每个位置与其他位置之间的关系(即注意力分数),使模型能够聚焦于输入序列中重要的部分。
  • 功能
    • 通过计算每个元素(如词)的加权表示,捕捉序列中元素之间的依赖关系。自注意力机制使得每个词可以根据上下文信息动态地调整自己的表示。
    • 允许模型在处理序列时不依赖于顺序,可以并行处理所有元素。
  • 实现方式
    1. 输入:每个输入位置的词嵌入 x 转换为三个向量:查询(Query)、键(Key)、值(Value)。

      Q=XWQ,K=XWK,V=XWV

      其中 WQ,WK,WV 是学习得到的权重矩阵,X 是输入矩阵。

    2. 计算注意力权重:计算查询 Q 和键 K 之间的点积,得到注意力分数:

      Attention(Q,K,V)=softmax(QKT/dk)V

      其中 dk 是键向量的维度,点积后进行缩放和 softmax 操作来得到归一化的注意力权重。

    3. 多头注意力:将上述计算扩展为多个注意力头,每个头都学习不同的表示,最后将它们拼接在一起并通过一个线性变换:MultiHead(Q,K,V)=Concat(head1,…,headh)WO

      每个头的计算是:

      headi=Attention(QWiQ,KWiK,VWiV)


9. 前馈神经网络层(Feed-Forward Network Layer, FFN)
  • 作用
    • 对每个位置的隐藏状态进行非线性变换,增加模型的表达能力。
  • 功能
    • 在每个位置上独立地应用一个前馈神经网络,通过非线性激活函数(如ReLU)来提高模型的复杂度和表达能力。前馈网络增强了模型对输入的转换能力,能够捕捉到更复杂的特征。
  • 实现方式
    1. 输入:每个位置的输入 x 来自上一层的输出。
    2. 两层全连接网络
      • 第一个全连接层将输入映射到一个更高维度(通常是 dff,比 dmodel 大):

        FFN1(x)=ReLU(xW1+b1)

      • 第二个全连接层将映射回原始维度 dmodel

        FFN2(x)=FFN1(x)W2+b2

    3. 输出:最终的输出 y 是通过第二个全连接层得到的输出,形状为 dmodel。
    • 激活函数:通常使用ReLU激活函数进行非线性转换。

1. Transformer架构中的核心算子

1.1 自注意力(Self-Attention)算子

自注意力是Transformer的核心计算单元,它通过计算输入序列中每个位置与其他位置之间的相关性来捕捉全局信息。其主要计算过程包括以下几个步骤:

  • 查询、键、值(Query, Key, Value)生成:
    • 通过输入序列与三个不同的权重矩阵相乘,生成查询(Q)、(K)和(V)向量:

      Q=XWQ,K=XWK,V=XWV

      其中,X 为输入序列,WQ、WK、WV 是学习的权重矩阵。

  • 注意力权重计算:
    • 计算注意力分数,通常采用缩放点积(Scaled Dot-Product)

      Attention(Q,K,V)=softmax(QKT/dk)V

      其中,dk 是查询和键的维度。

  • 多头注意力(Multi-Head Attention):
    • 多头注意力是对多个注意力头的计算结果进行并行处理,然后将其拼接在一起,并通过一个线性变换来得到最终结果:

      MultiHead(Q,K,V)=Concat(head1, head2, ..., headh)WO

      其中,headi=Attention(QWiQ, KWiK, VWiV),WO 是输出权重矩阵。

1.2 位置编码(Positional Encoding)

由于Transformer不具备卷积或循环神经网络(RNN)等结构来处理序列中的位置关系,因此需要额外的位置编码来提供位置信息。常见的位置编码方式为正余弦函数形式:

PE(pos,2i)=sin⁡(pos/100002i/d), PE(pos,2i+1)=cos(pos/100002i/d)

其中,pos 是词的位置,i 是维度索引,d 是向量的维度。

1.3 前馈神经网络(Feed-Forward Network, FFN)

Transformer中的每一层包含一个前馈神经网络,该网络通常包括两个线性变换层和一个非线性激活函数(如ReLU):

FFN(x)=max(0, xW1+b1)W2+b2

这里,W1、W2是线性层的权重矩阵,b1、b2 是偏置项,max(0,⋅)是ReLU激活函数。

1.4 层归一化(Layer Normalization)

层归一化在Transformer中被广泛用于在每一层的输出中进行归一化操作,以提高训练的稳定性和收敛速度。其计算公式为:

LayerNorm(x)=x−μ/σ⋅γ+β

其中,μ和 σ 分别是输入的均值和标准差,γ 和 β 是可学习的参数。

1.5 残差连接(Residual Connection)

在每一层的计算中,都有残差连接(即跳过连接),它可以帮助缓解深度网络的梯度消失问题。每一层的输出是输入和该层计算结果的和:

Output=Layer(x)+x

这种结构通常与层归一化一起使用。

2. 后续衍生的Transformer架构中的算子

随着Transformer架构的普及,衍生出了许多变种,它们在原始架构上进行了优化或扩展。以下是一些常见的衍生架构及其新增或修改的算子。

2.1 BERT(Bidirectional Encoder Representations from Transformers)
  • 双向注意力(Bidirectional Attention):
    • 在BERT中,模型通过掩蔽语言模型(Masked Language Model, MLM)进行预训练,使用了双向自注意力机制。这意味着每个位置的注意力不仅仅依赖于前面的位置,还依赖于后面的位置。
2.2 GPT(Generative Pretrained Transformer)
  • 自回归生成(Autoregressive Generation):
    • GPT使用自回归生成模型,这意味着每次生成的下一个词汇依赖于前面已经生成的词汇。因此,GPT仅使用单向自注意力
2.3 Transformer-XL(Transformer with Extra Long Context)
  • 相对位置编码(Relative Positional Encoding):
    • 为了处理更长的序列,Transformer-XL引入了相对位置编码,使得模型能够处理长序列,并在跨序列计算中共享位置依赖关系。
2.4 T5(Text-to-Text Transfer Transformer)
  • 统一文本到文本的框架:
    • T5采用了一个统一的框架,将所有NLP任务转化为“文本到文本”的任务。比如,文本分类被视为文本生成任务,通过输入指定的任务标签来引导模型生成相应的输出。
2.5 XLNet
  • 自回归与自编码联合模型(Autoregressive and Autoencoding):
    • XLNet结合了自回归(GPT-style)和自编码(BERT-style)模型,利用了一种新型的**排列语言建模(Permutation Language Modeling)**方法来提高性能。
2.6 RoBERTa
  • 大规模无监督预训练:
    • RoBERTa优化了BERT中的训练过程,通过去掉BERT中的某些限制(例如,去掉了Next Sentence Prediction任务),并且使用了更多的数据和更长的训练时间。
2.7 ALBERT(A Lite BERT)
  • 参数共享和低秩分解:
    • ALBERT通过在网络中共享权重来减少参数数量,同时引入低秩分解技术来优化模型的计算效率。
2.8 DistilBERT
  • 模型蒸馏(Knowledge Distillation):
    • DistilBERT是通过知识蒸馏从BERT中提取知识来生成一个更小的模型,保持了BERT的大部分性能,但减少了模型大小和计算量。
2.9 DETR(Detection Transformer)
  • 变换器用于目标检测:
    • DETR将Transformer应用于目标检测任务,摒弃了传统的区域提议网络(RPN)。它使用全局自注意力机制来直接预测目标位置和类别。
2.10 Swin Transformer
  • 滑动窗口(Window-based Self-Attention):
    • Swin Transformer采用局部的窗口注意力机制,通过滑动窗口的方式进行计算,从而提高计算效率,并且具有良好的性能,特别是在视觉任务中。
2.11 ViT(Vision Transformer)
  • 图像的分块处理:
    • ViT将图像分为固定大小的块(patches),然后将这些块输入到Transformer模型中,通过自注意力机制处理图像数据。

3 激活函数

1. 线性激活函数(Linear Activation Function)
  • 线性激活函数(Linear)
    • 公式: f(x)=xf(x) = xf(x)=x
    • 特点:输出与输入成正比,因此它不能引入非线性特征。在深度网络中使用线性激活函数可能会使得网络的能力受限,因此一般很少使用。
2. 非线性激活函数(Non-linear Activation Functions)

非线性激活函数通过引入非线性因素,使得神经网络能够学习和逼近复杂的非线性映射。以下是常见的非线性激活函数:

2.1 阶跃函数(Step Function)
  • 阶跃激活函数
    • 公式: f(x)={1,if x>00,if x≤0f(x) = \begin{cases} 1, & \text{if } x > 0 \\ 0, & \text{if } x \leq 0 \end{cases}f(x)={1,0,if x>0if x≤0
    • 特点:是最简单的非线性激活函数,输出是0或1。它在训练过程中不容易使用,因为其导数为零,不利于梯度下降的学习。
2.2 Sigmoid 激活函数
  • Sigmoid 函数
    • 公式: f(x)=11+e−xf(x) = \frac{1}{1 + e^{-x}}f(x)=1+e−x1
    • 特点:将输出压缩到 [0, 1] 区间内,常用于二分类问题的输出层。
    • 问题:Sigmoid 的导数容易饱和,导致梯度消失问题,且输出值不以零为中心。
2.3 双曲正切(Tanh)激活函数
  • Tanh 函数
    • 公式: f(x)=tanh⁡(x)=ex−e−xex+e−xf(x) = \tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}f(x)=tanh(x)=ex+e−xex−e−x
    • 特点:输出范围是 [-1, 1],相较于 Sigmoid,Tanh 输出是以零为中心的,通常能得到更好的训练效果。
    • 问题:与 Sigmoid 类似,Tanh 也会遇到梯度消失问题。
2.4 ReLU(Rectified Linear Unit)激活函数
  • ReLU
    • 公式: f(x)=max⁡(0,x)f(x) = \max(0, x)f(x)=max(0,x)
    • 特点:输出非负数(0或正值)。ReLU 在正区间是线性的,可以有效缓解梯度消失问题,并且计算效率高。
    • 问题:在训练过程中,若输入值为负,ReLU 输出为零,可能导致“神经元死亡”(Dead Neurons)问题。
2.5 Leaky ReLU
  • Leaky ReLU
    • 公式: f(x)={x,if x>0αx,if x≤0f(x) = \begin{cases} x, & \text{if } x > 0 \\ \alpha x, & \text{if } x \leq 0 \end{cases}f(x)={x,αx,if x>0if x≤0
    • 特点:与 ReLU 相似,但对负输入也有一定的输出,避免了“神经元死亡”问题。
    • 参数:α\alphaα 是一个很小的常数,通常设置为 0.01。
2.6 Parametric ReLU (PReLU)
  • PReLU
    • 公式: f(x)={x,if x>0αx,if x≤0f(x) = \begin{cases} x, & \text{if } x > 0 \\ \alpha x, & \text{if } x \leq 0 \end{cases}f(x)={x,αx,if x>0if x≤0
    • 特点:与 Leaky ReLU 相似,但是 α\alphaα 不是一个固定值,而是一个可学习的参数。
2.7 Exponential Linear Unit (ELU)
  • ELU
    • 公式: f(x)={x,if x≥0α(ex−1),if x<0f(x) = \begin{cases} x, & \text{if } x \geq 0 \\ \alpha (e^x - 1), & \text{if } x < 0 \end{cases}f(x)={x,α(ex−1),if x≥0if x<0
    • 特点:在负区间输出为负数,有助于减小偏移,并且对负输入有平滑过渡。
    • 参数:α\alphaα 是超参数。
2.8 Scaled Exponential Linear Unit (SELU)
  • SELU
    • 公式:与 ELU 类似,但具有自归一化特性,适合用于深度网络。
    • 特点:在深度神经网络中,SELU 通过自归一化过程保持了梯度传播的稳定性。

3. 输出层激活函数

这些激活函数通常用于特定任务的输出层。

3.1 Softmax 激活函数
  • Softmax
    • 公式: pi=ezi∑j=1nezjp_i = \frac{e^{z_i}}{\sum_{j=1}^n e^{z_j}}pi=∑j=1nezjezi
    • 特点:用于多类分类任务,输出为概率分布,所有输出的和为1。
    • 应用:广泛用于多类分类问题的输出层。
3.2 Sigmoid 激活函数(用于输出层)
  • Sigmoid
    • 公式: f(x)=11+e−xf(x) = \frac{1}{1 + e^{-x}}f(x)=1+e−x1
    • 特点:将输出压缩到 [0, 1] 区间,常用于二分类问题的输出层。
3.3 硬 sigmoid(Hard Sigmoid)
  • 硬 Sigmoid
    • 公式: f(x)=max⁡(0,min⁡(1,x+12))f(x) = \max(0, \min(1, \frac{x + 1}{2}))f(x)=max(0,min(1,2x+1))
    • 特点:类似于 Sigmoid,但计算更加高效。

4. 其他激活函数
4.1 Swish
  • Swish
    • 公式: f(x)=x⋅σ(x)f(x) = x \cdot \sigma(x)f(x)=x⋅σ(x)
    • 特点:由 Google 提出,Swish 是一个连续且可微的激活函数,比 ReLU 和 Tanh 在很多任务上效果更好。
4.2 Mish
  • Mish
    • 公式: f(x)=x⋅tanh⁡(softplus(x))f(x) = x \cdot \tanh(\text{softplus}(x))f(x)=x⋅tanh(softplus(x))
    • 特点:Mish 函数通过引入连续和可导的激活方式,使得神经网络能够更好地进行训练和优化,常用于提升模型的性能。
4.3 GELU (Gaussian Error Linear Unit)
  • GELU
    • 公式: f(x)=0.5x(1+tanh⁡(2π(x+0.044715x3)))f(x) = 0.5x(1 + \tanh(\sqrt{\frac{2}{\pi}}(x + 0.044715x^3)))f(x)=0.5x(1+tanh(π2(x+0.044715x3)))
    • 特点:GELU 在Transformer等大型预训练模型中被广泛使用。与ReLU类似,但对负值的处理更加平滑。