docs:第二章 Transformers 架构 修复
This commit is contained in:
@@ -4,46 +4,46 @@
|
||||
|
||||
### 2.1.1 什么是注意力机制
|
||||
|
||||
随着 NLP 从统计机器学习向深度学习迈进,作为 NLP 核心问题的文本表示方法也逐渐从统计学习向深度学习迈进。正如我们在第一章所介绍的,文本表示从最初的通过统计学习模型进行计算的向量空间模型、语言模型,通过 Word2Vec 的单层神经网络进入到通过神经网络学习文本表示的时代。但是,从 CV(Computer Vision,计算机视觉)为起源发展起来的神经网络,其核心架构有三种:
|
||||
随着 NLP 从统计机器学习向深度学习迈进,作为 NLP 核心问题的文本表示方法也逐渐从统计学习向深度学习迈进。正如我们在第一章所介绍的,文本表示从最初的通过统计学习模型进行计算的向量空间模型、语言模型,通过 Word2Vec 的单层神经网络进入到通过神经网络学习文本表示的时代。但是,从 计算机视觉(Computer Vision,CV)为起源发展起来的神经网络,其核心架构有三种:
|
||||
|
||||
- 全连接网络(FNN),即每一层的神经元都和上下两层的每一个神经元完全连接:
|
||||
- 前馈神经网络(Feedforward Neural Network,FNN),即每一层的神经元都和上下两层的每一个神经元完全连接,如图2.1所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/1-0.png" alt="图片描述" width="90%"/>
|
||||
<p>图1. 全链接网络</p>
|
||||
<p>图2.1 前馈神经网络</p>
|
||||
</div>
|
||||
|
||||
- 卷积神经网络(CNN),即训练参数量远小于全连接层的卷积层来进行特征提取和学习:
|
||||
- 卷积神经网络(Convolutional Neural Network,CNN),即训练参数量远小于前馈神经网络的卷积层来进行特征提取和学习,如图2.2所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/1-1.png" alt="图片描述" width="90%"/>
|
||||
<p>图2. 卷积神经网络</p>
|
||||
<p>图2.2 卷积神经网络</p>
|
||||
</div>
|
||||
|
||||
- 循环神经网络(RNN),能够使用历史信息作为输入、包含环和自重复的网络:
|
||||
- 循环神经网络(Recurrent Neural Network,RNN),能够使用历史信息作为输入、包含环和自重复的网络,如图2.3所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/1-2.png" alt="图片描述" width="90%"/>
|
||||
<p>图3. 循环神经网络</p>
|
||||
<p>图2.3 循环神经网络</p>
|
||||
</div>
|
||||
|
||||
由于 NLP 任务所需要处理的文本往往是序列,因此专用于处理序列、时序数据的 RNN 往往能够在 NLP 任务上取得最优的效果。事实上,在注意力机制横空出世之前,RNN 以及 RNN 的衍生架构 LSTM 是 NLP 领域当之无愧的霸主。例如,我们在第一章讲到过的开创了预训练思想的文本表示模型 ELMo,就是使用的双向 LSTM 作为网络架构。
|
||||
|
||||
但 RNN 及 LSTM 虽然具有捕捉时序信息、适合序列生成的优点,却有两个难以弥补的缺陷:
|
||||
|
||||
1. 序列依序计算的模式能够很好地模拟时序信息,但限制了计算机并行计算的能力。由于序列需要依次输入、依序计算,GPU 并行计算的能力受到了极大限制,导致 RNN 为基础架构的模型虽然参数量不算特别大,但计算时间成本却很高;
|
||||
1. 序列依序计算的模式能够很好地模拟时序信息,但限制了计算机并行计算的能力。由于序列需要依次输入、依序计算,图形处理器(Graphics Processing Unit,GPU)并行计算的能力受到了极大限制,导致 RNN 为基础架构的模型虽然参数量不算特别大,但计算时间成本却很高;
|
||||
|
||||
2. RNN 难以捕捉长序列的相关关系。在 RNN 架构中,距离越远的输入之间的关系就越难被捕捉,同时 RNN 需要将整个序列读入内存依次计算,也限制了序列的长度。虽然 LSTM 中通过门机制对此进行了一定优化,但对于较远距离相关关系的捕捉,RNN 依旧是不如人意的。
|
||||
|
||||
针对这样的问题,Vaswani 等学者参考了在 CV 领域被提出、被经常融入到 RNN 中使用的注意力机制(注意,虽然注意力机制在 NLP 被发扬光大,但其确实是在 CV 领域被提出的),创新性地搭建了完全由注意力机制构成的神经网络——Transformer,也就是 LLM 的鼻祖及核心架构,从而让注意力机制一跃成为深度学习最核心的架构之一。
|
||||
针对这样的问题,Vaswani 等学者参考了在 CV 领域被提出、被经常融入到 RNN 中使用的注意力机制(Attention)(注意,虽然注意力机制在 NLP 被发扬光大,但其确实是在 CV 领域被提出的),创新性地搭建了完全由注意力机制构成的神经网络——Transformer,也就是大语言模型(Large Language Model,LLM)的鼻祖及核心架构,从而让注意力机制一跃成为深度学习最核心的架构之一。
|
||||
|
||||
那么,究竟什么是注意力机制(Attention)?
|
||||
那么,究竟什么是注意力机制?
|
||||
|
||||
Attention 机制最先源于计算机视觉领域,其核心思想为当我们关注一张图片,我们往往无需看清楚全部内容而仅将注意力集中在重点部分即可。而在自然语言处理领域,我们往往也可以通过将重点注意力集中在一个或几个 token,从而取得更高效高质的计算效果。
|
||||
注意力机制最先源于计算机视觉领域,其核心思想为当我们关注一张图片,我们往往无需看清楚全部内容而仅将注意力集中在重点部分即可。而在自然语言处理领域,我们往往也可以通过将重点注意力集中在一个或几个 token,从而取得更高效高质的计算效果。
|
||||
|
||||
Attention 机制有三个核心变量:**Query**(查询值)、**Key**(键值)和 **Value**(真值)。我们可以通过一个案例来理解每一个变量所代表的含义。例如,当我们有一篇新闻报道,我们想要找到这个报道的时间,那么,我们的 Query 可以是类似于“时间”、“日期”一类的向量(为了便于理解,此处使用文本来表示,但其实际是稠密的向量),Key 和 Value 会是整个文本。通过对 Query 和 Key 进行运算我们可以得到一个权重,这个权重其实反映了从 Query 出发,对文本每一个 token 应该分布的注意力相对大小。通过把权重和 Value 进行运算,得到的最后结果就是从 Query 出发计算整个文本注意力得到的结果。
|
||||
注意力机制有三个核心变量:**Query**(查询值)、**Key**(键值)和 **Value**(真值)。我们可以通过一个案例来理解每一个变量所代表的含义。例如,当我们有一篇新闻报道,我们想要找到这个报道的时间,那么,我们的 Query 可以是类似于“时间”、“日期”一类的向量(为了便于理解,此处使用文本来表示,但其实际是稠密的向量),Key 和 Value 会是整个文本。通过对 Query 和 Key 进行运算我们可以得到一个权重,这个权重其实反映了从 Query 出发,对文本每一个 token 应该分布的注意力相对大小。通过把权重和 Value 进行运算,得到的最后结果就是从 Query 出发计算整个文本注意力得到的结果。
|
||||
|
||||
具体而言,Attention 机制的特点是通过计算 **Query** 与**Key**的相关性为真值加权求和,从而拟合序列中每个词同其他词的相关关系。
|
||||
具体而言,注意力机制的特点是通过计算 **Query** 与**Key**的相关性为真值加权求和,从而拟合序列中每个词同其他词的相关关系。
|
||||
|
||||
### 2.1.2 深入理解注意力机制
|
||||
|
||||
@@ -99,7 +99,7 @@ $$attention(Q,K,V) = softmax(qK^T)v$$
|
||||
|
||||
$$attention(Q,K,V) = softmax(QK^T)V$$
|
||||
|
||||
目前,我们离标准的注意力公式还差最后一步。在上一个公式中,如果 Q 和 K 对应的维度 $d_k$ 比较大,softmax 放缩时就非常容易受影响,使不同值之间的差异较大,从而影响梯度的稳定性。因此,我们要将 Q 和 K 乘积的结果做一个放缩:
|
||||
目前,我们离标准的注意力机制公式还差最后一步。在上一个公式中,如果 Q 和 K 对应的维度 $d_k$ 比较大,softmax 放缩时就非常容易受影响,使不同值之间的差异较大,从而影响梯度的稳定性。因此,我们要将 Q 和 K 乘积的结果做一个放缩:
|
||||
|
||||
$$attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k}})V$$
|
||||
|
||||
@@ -133,15 +133,15 @@ def attention(query, key, value, dropout=None):
|
||||
|
||||
```
|
||||
|
||||
注意,在上文代码中,我们假设输入的 q、k、v 是已经经过转化的词向量矩阵,也就是公式中的 Q、K、V。我们仅需要通过上述几行代码,就可以实现核心的 attention 计算。
|
||||
注意,在上文代码中,我们假设输入的 q、k、v 是已经经过转化的词向量矩阵,也就是公式中的 Q、K、V。我们仅需要通过上述几行代码,就可以实现核心的注意力机制计算。
|
||||
|
||||
### 2.1.4 自注意力
|
||||
|
||||
根据上文的分析,我们可以发现,Attention 机制的本质是对两段序列的元素依次进行相似度计算,寻找出一个序列的每个元素对另一个序列的每个元素的相关度,然后基于相关度进行加权,即分配注意力。而这两段序列即是我们计算过程中 Q、K、V 的来源。
|
||||
根据上文的分析,我们可以发现,注意力机制的本质是对两段序列的元素依次进行相似度计算,寻找出一个序列的每个元素对另一个序列的每个元素的相关度,然后基于相关度进行加权,即分配注意力。而这两段序列即是我们计算过程中 Q、K、V 的来源。
|
||||
|
||||
但是,在我们的实际应用中,我们往往只需要计算 Query 和 Key 之间的注意力结果,很少存在额外的真值 Value。也就是说,我们其实只需要拟合两个文本序列。在经典的 Attention 机制中,Q 往往来自于一个序列,K 与 V 来自于另一个序列,都通过参数矩阵计算得到,从而可以拟合这两个序列之间的关系。例如在 Transformer 的 Decoder 结构中,Q 来自于 Encoder 的输出,K 与 V 来自于 Decoder 的输入,从而拟合了编码信息与历史信息之间的关系,便于综合这两种信息实现未来的预测。
|
||||
但是,在我们的实际应用中,我们往往只需要计算 Query 和 Key 之间的注意力结果,很少存在额外的真值 Value。也就是说,我们其实只需要拟合两个文本序列。在经典的 注意力机制中,Q 往往来自于一个序列,K 与 V 来自于另一个序列,都通过参数矩阵计算得到,从而可以拟合这两个序列之间的关系。例如在 Transformer 的 Decoder 结构中,Q 来自于 Encoder 的输出,K 与 V 来自于 Decoder 的输入,从而拟合了编码信息与历史信息之间的关系,便于综合这两种信息实现未来的预测。
|
||||
|
||||
但在 Transformer 的 Encoder 结构中,使用的是 Attention 机制的变种 —— self-attention (自注意力)机制。所谓自注意力,即是计算本身序列中每个元素都其他元素的注意力分布,即在计算过程中,Q、K、V 都由同一个输入通过不同的参数矩阵计算得到。在 Encoder 中,Q、K、V 分别是输入对参数矩阵 $W_q$、$W_k$、$W_v$ 做积得到,从而拟合输入语句中每一个 token 对其他所有 token 的关系。
|
||||
但在 Transformer 的 Encoder 结构中,使用的是 注意力机制的变种 —— 自注意力(self-attention,自注意力)机制。所谓自注意力,即是计算本身序列中每个元素都其他元素的注意力分布,即在计算过程中,Q、K、V 都由同一个输入通过不同的参数矩阵计算得到。在 Encoder 中,Q、K、V 分别是输入对参数矩阵 $W_q$、$W_k$、$W_v$ 做积得到,从而拟合输入语句中每一个 token 对其他所有 token 的关系。
|
||||
|
||||
通过自注意力机制,我们可以找到一段文本中每一个 token 与其他所有 token 的相关关系大小,从而建模文本之间的依赖关系。在代码中的实现,self-attention 机制其实是通过给 Q、K、V 的输入传入同一个参数实现的:
|
||||
|
||||
@@ -152,7 +152,7 @@ attention(x, x, x)
|
||||
|
||||
### 2.1.5 掩码自注意力
|
||||
|
||||
掩码自注意力,即 Mask Self Attention,是指使用注意力掩码的自注意力机制。掩码的作用是遮蔽一些特定位置的 token,模型在学习的过程中,会忽略掉被遮蔽的 token。
|
||||
掩码自注意力,即 Mask Self-Attention,是指使用注意力掩码的自注意力机制。掩码的作用是遮蔽一些特定位置的 token,模型在学习的过程中,会忽略掉被遮蔽的 token。
|
||||
|
||||
使用注意力掩码的核心动机是让模型只能使用历史信息进行预测而不能看到未来信息。使用注意力机制的 Transformer 模型也是通过类似于 n-gram 的语言模型任务来学习的,也就是对一个文本序列,不断根据之前的 token 来预测下一个 token,直到将整个文本序列补全。
|
||||
|
||||
@@ -199,17 +199,17 @@ scores = scores + mask[:, :seqlen, :seqlen]
|
||||
scores = F.softmax(scores.float(), dim=-1).type_as(xq)
|
||||
```
|
||||
|
||||
通过做求和,上三角区域(也就是应该被遮蔽的 token 对应的位置)的注意力分数结果都变成了 -inf,而下三角区域的分数不变。再做 Softmax 操作,-inf 的值在经过 Softmax 之后会被置为 0,从而忽略了上三角区域计算的注意力分数,从而实现了注意力遮蔽。
|
||||
通过做求和,上三角区域(也就是应该被遮蔽的 token 对应的位置)的注意力分数结果都变成了 `-inf`,而下三角区域的分数不变。再做 Softmax 操作,`-inf` 的值在经过 Softmax 之后会被置为 0,从而忽略了上三角区域计算的注意力分数,从而实现了注意力遮蔽。
|
||||
|
||||
### 2.1.6 多头注意力
|
||||
|
||||
注意力机制可以实现并行化与长期依赖关系拟合,但一次注意力计算只能拟合一种相关关系,单一的注意力机制很难全面拟合语句序列里的相关关系。因此 Transformer 使用了 Multi-Head attention,也就是多头注意力机制,即同时对一个语料进行多次注意力计算,每次注意力计算都能拟合不同的关系,将最后的多次结果拼接起来作为最后的输出,即可更全面深入地拟合语言信息。
|
||||
注意力机制可以实现并行化与长期依赖关系拟合,但一次注意力计算只能拟合一种相关关系,单一的注意力机制很难全面拟合语句序列里的相关关系。因此 Transformer 使用了多头注意力机制(Multi-Head Attention),即同时对一个语料进行多次注意力计算,每次注意力计算都能拟合不同的关系,将最后的多次结果拼接起来作为最后的输出,即可更全面深入地拟合语言信息。
|
||||
|
||||
在原论文中,作者也通过实验证实,多头注意力计算中,每个不同的注意力头能够拟合语句中的不同信息,如下图:
|
||||
在原论文中,作者也通过实验证实,多头注意力计算中,每个不同的注意力头能够拟合语句中的不同信息,如图2.4所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/1-3.jpeg" alt="图片描述" width="90%"/>
|
||||
<p>图4. 多头注意力机制</p>
|
||||
<p>图2.4 多头注意力机制</p>
|
||||
</div>
|
||||
|
||||
上层与下层分别是两个注意力头对同一段语句序列进行自注意力计算的结果,可以看到,对于不同的注意力头,能够拟合不同层次的相关信息。通过多个注意力头同时计算,能够更全面地拟合语句关系。
|
||||
@@ -317,9 +317,9 @@ class MultiHeadAttention(nn.Module):
|
||||
|
||||
## 2.2 Encoder-Decoder
|
||||
|
||||
在上一节,我们详细介绍了 Transformer 的核心——Attention 机制。在《Attention is All You Need》一文中,作者通过仅使用 Attention 而抛弃传统的 RNN、CNN 架构搭建出 Transformer 模型,从而带来了 NLP 领域的大变革。在 Transformer 中,使用 Attention 机制的是其两个核心组件——Encoder(编码器)和 Decoder(解码器)。事实上,后续基于 Transformer 架构而来的预训练语言模型基本都是对 Encoder-Decoder 部分进行改进来构建新的模型架构,例如只使用 Encoder 的 BERT、只使用 Decoder 的 GPT 等。
|
||||
在上一节,我们详细介绍了 Transformer 的核心——注意力机制。在《Attention is All You Need》一文中,作者通过仅使用注意力机制而抛弃传统的 RNN、CNN 架构搭建出 Transformer 模型,从而带来了 NLP 领域的大变革。在 Transformer 中,使用注意力机制的是其两个核心组件——Encoder(编码器)和 Decoder(解码器)。事实上,后续基于 Transformer 架构而来的预训练语言模型基本都是对 Encoder-Decoder 部分进行改进来构建新的模型架构,例如只使用 Encoder 的 BERT、只使用 Decoder 的 GPT 等。
|
||||
|
||||
在本节中,我们将以上一节所介绍的 Attention 机制为基础,从 Transformer 所针对的 Seq2Seq 任务出发,解析 Transformer 的 Encoder-Decoder 结构。
|
||||
在本节中,我们将以上一节所介绍的 注意力机制为基础,从 Transformer 所针对的 Seq2Seq 任务出发,解析 Transformer 的 Encoder-Decoder 结构。
|
||||
|
||||
### 2.2.1 Seq2Seq 模型
|
||||
|
||||
@@ -329,24 +329,24 @@ Seq2Seq,即序列到序列,是一种经典 NLP 任务。具体而言,是
|
||||
|
||||
对于 Seq2Seq 任务,一般的思路是对自然语言序列进行编码再解码。所谓编码,就是将输入的自然语言序列通过隐藏层编码成能够表征语义的向量(或矩阵),可以简单理解为更复杂的词向量表示。而解码,就是对输入的自然语言序列编码得到的向量或矩阵通过隐藏层输出,再解码成对应的自然语言目标序列。通过编码再解码,就可以实现 Seq2Seq 任务。
|
||||
|
||||
Transformer 中的 Encoder,就是用于上述的编码过程;Decoder 则用于上述的解码过程。Transformer 结构如下图:
|
||||
Transformer 中的 Encoder,就是用于上述的编码过程;Decoder 则用于上述的解码过程。Transformer 结构,如图2.5所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/2-0.jpg" alt="图片描述" width="90%"/>
|
||||
<p>图5. 编码器-解码器结构</p>
|
||||
<p>图2.5 编码器-解码器结构</p>
|
||||
</div>
|
||||
|
||||
Transformer 由 Encoder 和 Decoder 组成,每一个 Encoder(Decoder)又由 6个 Encoder(Decoder)Layer 组成。输入源序列会进入 Encoder 进行编码,到 Encoder Layer 的最顶层再将编码结果输出给 Decoder Layer 的每一层,通过 Decoder 解码后就可以得到输出目标序列了。
|
||||
|
||||
接下来,我们将首先介绍 Encoder 和 Decoder 内部传统神经网络的经典结构——全连接网络(FNN)、层归一化(Layer Norm)和残差连接(Residual Connection),然后进一步分析 Encoder 和 Decoder 的内部结构。
|
||||
接下来,我们将首先介绍 Encoder 和 Decoder 内部传统神经网络的经典结构——前馈神经网络(FNN)、层归一化(Layer Norm)和残差连接(Residual Connection),然后进一步分析 Encoder 和 Decoder 的内部结构。
|
||||
|
||||
### 2.2.2 全连接网络
|
||||
### 2.2.2 前馈神经网络
|
||||
|
||||
全连接网络(Full Neural Network,下简称 FNN),也就是我们在上一节提过的每一层的神经元都和上下两层的每一个神经元完全连接的网络结构。每一个 Encoder Layer 都包含一个上文讲的注意力机制和一个全连接层。全连接层的实现是较为简单的:
|
||||
前馈神经网络(Feed Forward Neural Network,下简称 FFN),也就是我们在上一节提过的每一层的神经元都和上下两层的每一个神经元完全连接的网络结构。每一个 Encoder Layer 都包含一个上文讲的注意力机制和一个前馈神经网络。前馈神经网络的实现是较为简单的:
|
||||
|
||||
```python
|
||||
class MLP(nn.Module):
|
||||
'''全连接层'''
|
||||
'''前馈神经网络'''
|
||||
def __init__(self, dim: int, hidden_dim: int, dropout: float):
|
||||
super().__init__()
|
||||
# 定义第一层线性变换,从输入维度到隐藏维度
|
||||
@@ -365,7 +365,7 @@ class MLP(nn.Module):
|
||||
|
||||
```
|
||||
|
||||
注意,Transformer 的全连接层是由两个线性层中间加一个 RELU 激活函数组成的,以及全连接层还加入了一个 Dropout 层来防止过拟合。
|
||||
注意,Transformer 的前馈神经网络是由两个线性层中间加一个 RELU 激活函数组成的,以及前馈神经网络还加入了一个 Dropout 层来防止过拟合。
|
||||
|
||||
### 2.2.3 层归一化
|
||||
|
||||
@@ -436,16 +436,16 @@ $$
|
||||
```python
|
||||
# 注意力计算
|
||||
h = x + self.attention.forward(self.attention_norm(x))
|
||||
# 经过全连接网络
|
||||
# 经过前馈神经网络
|
||||
out = h + self.feed_forward.forward(self.fnn_norm(h))
|
||||
```
|
||||
|
||||
在上文代码中,self.attention_norm 和 self.fnn_norm 都是 LayerNorm 层,self.attn 是注意力层,而 self.feed_forward 是全连接层。
|
||||
在上文代码中,self.attention_norm 和 self.fnn_norm 都是 LayerNorm 层,self.attn 是注意力层,而 self.feed_forward 是前馈神经网络。
|
||||
|
||||
### 2.2.5 Encoder
|
||||
|
||||
|
||||
在实现上述组件之后,我们可以搭建起 Transformer 的 Encoder。Encoder 由 N 个 Encoder Layer 组成,每一个 Encoder Layer 包括一个注意力层和一个全连接层。因此,我们可以首先实现一个 Encoder Layer:
|
||||
在实现上述组件之后,我们可以搭建起 Transformer 的 Encoder。Encoder 由 N 个 Encoder Layer 组成,每一个 Encoder Layer 包括一个注意力层和一个前馈神经网络。因此,我们可以首先实现一个 Encoder Layer:
|
||||
|
||||
```python
|
||||
class EncoderLayer(nn.Module):
|
||||
@@ -464,7 +464,7 @@ class EncoderLayer(nn.Module):
|
||||
x = self.attention_norm(x)
|
||||
# 自注意力
|
||||
h = x + self.attention.forward(x, x, x)
|
||||
# 经过全连接网络
|
||||
# 经过前馈神经网络
|
||||
out = h + self.feed_forward.forward(self.fnn_norm(h))
|
||||
return out
|
||||
```
|
||||
@@ -491,7 +491,7 @@ class Encoder(nn.Module):
|
||||
|
||||
### 2.2.6 Decoder
|
||||
|
||||
类似的,我们也可以先搭建 Decoder Layer,再将 N 个 Decoder Layer 组装为 Decoder。但是和 Encoder 不同的是,Decoder 由两个注意力层和一个全连接层组成。第一个注意力层是一个掩码自注意力层,即使用 Mask 的注意力计算,保证每一个 token 只能使用该 token 之前的注意力分数;第二个注意力层是一个多头注意力层,该层将使用第一个注意力层的输出作为 query,使用 Encoder 的输出作为 key 和 value,来计算注意力分数。最后,再经过全连接层:
|
||||
类似的,我们也可以先搭建 Decoder Layer,再将 N 个 Decoder Layer 组装为 Decoder。但是和 Encoder 不同的是,Decoder 由两个注意力层和一个前馈神经网络组成。第一个注意力层是一个掩码自注意力层,即使用 Mask 的注意力计算,保证每一个 token 只能使用该 token 之前的注意力分数;第二个注意力层是一个多头注意力层,该层将使用第一个注意力层的输出作为 query,使用 Encoder 的输出作为 key 和 value,来计算注意力分数。最后,再经过前馈神经网络:
|
||||
|
||||
```python
|
||||
class DecoderLayer(nn.Module):
|
||||
@@ -517,7 +517,7 @@ class DecoderLayer(nn.Module):
|
||||
# 多头注意力
|
||||
x = self.attention_norm_2(x)
|
||||
h = x + self.attention.forward(x, enc_out, enc_out)
|
||||
# 经过全连接网络
|
||||
# 经过前馈神经网络
|
||||
out = h + self.feed_forward.forward(self.fnn_norm(h))
|
||||
return out
|
||||
```
|
||||
@@ -579,9 +579,9 @@ self.tok_embeddings = nn.Embedding(args.vocab_size, args.dim)
|
||||
|
||||
### 2.3.2 位置编码
|
||||
|
||||
Attention 机制可以实现良好的并行计算,但同时,其注意力计算的方式也导致序列中相对位置的丢失。在 RNN、LSTM 中,输入序列会沿着语句本身的顺序被依次递归处理,因此输入序列的顺序提供了极其重要的信息,这也和自然语言的本身特性非常吻合。
|
||||
注意力机制可以实现良好的并行计算,但同时,其注意力计算的方式也导致序列中相对位置的丢失。在 RNN、LSTM 中,输入序列会沿着语句本身的顺序被依次递归处理,因此输入序列的顺序提供了极其重要的信息,这也和自然语言的本身特性非常吻合。
|
||||
|
||||
但从上文对 Attention 机制的分析我们可以发现,在 Attention 机制的计算过程中,对于序列中的每一个 token,其他各个位置对其来说都是平等的,即“我喜欢你”和“你喜欢我”在 Attention 机制看来是完全相同的,但无疑这是 Attention 机制存在的一个巨大问题。因此,为使用序列顺序信息,保留序列中的相对位置信息,Transformer 采用了位置编码机制,该机制也在之后被多种模型沿用。
|
||||
但从上文对注意力机制的分析我们可以发现,在注意力机制的计算过程中,对于序列中的每一个 token,其他各个位置对其来说都是平等的,即“我喜欢你”和“你喜欢我”在注意力机制看来是完全相同的,但无疑这是注意力机制存在的一个巨大问题。因此,为使用序列顺序信息,保留序列中的相对位置信息,Transformer 采用了位置编码机制,该机制也在之后被多种模型沿用。
|
||||
|
||||
位置编码,即根据序列中 token 的相对位置对其进行编码,再将位置编码加入词向量编码中。位置编码的方式有很多,Transformer 使用了正余弦函数来进行位置编码(绝对位置编码Sinusoidal),其编码方式为:
|
||||
|
||||
@@ -677,11 +677,11 @@ $$
|
||||
|
||||
说明该编码仍然可以表示相对位置。
|
||||
|
||||
上述编码结果示例如下:
|
||||
上述编码结果,如图2.6所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/3-0.png" alt="图片描述" width="90%"/>
|
||||
<p>图6. 编码结果</p>
|
||||
<p>图2.6 编码结果</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -718,11 +718,11 @@ class PositionalEncoding(nn.Module):
|
||||
|
||||
### 2.3.3 一个完整的 Transformer
|
||||
|
||||
上述所有组件,再按照下图的 Tranfromer 结构拼接起来就是一个完整的 Transformer 模型啦:
|
||||
上述所有组件,再按照下图的 Tranfromer 结构拼接起来就是一个完整的 Transformer 模型了,如图2.7所示:
|
||||
|
||||
<div align="center">
|
||||
<img src="./figures/3-1.png" alt="图片描述" width="80%"/>
|
||||
<p>图7. Transformer 模型结构</p>
|
||||
<p>图2.7 Transformer 模型结构</p>
|
||||
</div>
|
||||
|
||||
如图,经过 tokenizer 映射后的输出先经过 Embedding 层和 Positional Embedding 层编码,然后进入上一节讲过的 N 个 Encoder 和 N 个 Decoder(在 Transformer 原模型中,N 取为6),最后经过一个线性层和一个 Softmax 层就得到了最终输出。
|
||||
|
||||
Reference in New Issue
Block a user