深度学习中的注意力模型是一种模拟人类视觉注意力机制的方法,它可以帮助我们更好地关注输入序列中的重要部分。近年来,注意力模型在深度学习各个领域被广泛使用,无论是在图像处理、语音识别还是自然语言处理的各种不同类型的任务中,都很容易遇到注意力模型的身影。
常见的深度学习中的注意力模型包括:自注意力机制、交互注意力机制、门控循环单元(GRU)和变压器(Transformer)等。但是无论其组成结构如何,构成的模块有哪些,其最基本的工作就是对输入的数据进行特征抽取,对原有的数据形式进行编码处理,并将其转换为特定类型的数据结构。对此,作者将这类模型统一称为“编码器”。
编码器是基于深度学习注意力构造的一种能够存储输入数据的若干特征的表达方式。虽然这些特征的具体内容是由深度学习模型进行提取的,即进行“黑盒”处理,但是通过对“编码器”的设计会使得模型可以自行决定关注哪些是对结果影响最为重要的内容。
在实践中,编码器是一种神经网络模型,一般由多个神经网络“模块”组成,其作用是将输入数据重整成一个多维特征矩阵,以便更好地进行分类、回归或生成等任务。常用的编码器通常由多个卷积层、池化层和全连接层组成,其中卷积层和池化层可以提取输入数据的特征,全连接层可以将特征转换为低维向量,而“注意力机制”则是这个编码器的核心模块。
在基于自注意力的编码器中,编码器的作用是将输入数据重整成一个多维向量,并在此基础上生成一个与原始输入数据相似的重构数据。这种自编码器模型可以用于图像去噪、图像分割、图像恢复等任务中。
为了简便起见,作者直接使用经典的编码器方案(即基于注意力机制的模型架构)作为本章编码器的实现。编码器的结构如图3-12所示。
图3-12 编码器结构示意图
从图3-12可见,本章编码器的结构是由以下多个模块构成的:
● 初始词向量层(Input Embedding)。
● 位置编码器层(Positional Encoding)。
● 多头自注意力层(Multi-Head Attention)。
● 归一化层(Layer Normalization)。
● 前馈层(Feed Forward Network)。
编码器通过使用多个不同的神经网络模块来获取需要关注的内容,并抑制和减弱其他无用信息,从而实现对特征的抽取,这也是目前最为常用的架构方案。
从上面编码器结构的示意图中可以看到,一个编码器的构造分成5部分:初始向量层、位置编码层、多头自注意力层、归一化层和前馈层。
多头自注意力层和归一化层在3.1节已经讲解完毕,接下来将介绍剩余的3个部分,之后将使用这3个部分构件出本书的编码器架构。
初始词向量层和位置编码器层是数据输入最初的层,作用是将输入的序列通过计算组合成向量矩阵,如图3-13所示。
图3-13 输入层
可以看到,这里的输入编码实际上是由两部分组成的,即位置向量编码和词向量编码。下面对每一部分依次进行讲解。
如同大多数的向量构建方法一样,首先将每个输入单词通过词映射算法转换为词向量。
其中每个词向量被设定为固定的维度,本书后面将所有词向量的维度设置为768。具体代码如下:
#请注意代码解释在代码段的下方 import torch word_embedding_table = torch.nn.Embedding(num_embeddings=encoder_vocab_size, embedding_dim=768) encoder_embedding = word_embedding_table(inputs)
这里对代码进行解释。首先,使用torch.nn.Embedding函数创建了一个随机初始化的向量矩阵。encoder_vocab_size是字库的大小,它通常包含编码器中所有可能出现的“字”。而embedding_dim是定义的嵌入向量的维度,这里使用通用的768维即可。
在PyTorch中,词向量的初始化只发生在最底层的编码器中。需要额外说明的是,所有编码器都有一个共同的特点:它们接收一个向量列表,列表中的每个向量大小为768维。在底层(最开始)的编码器中,这些向量是词向量;而在其他编码器中,这些向量则是上一层编码器的输出(仍然是一个向量列表)。
位置编码是一个非常重要且具有创新性的结构输入。在自然语言处理中,输入通常是一个个连续的序列,因此为了利用输入的顺序信息,需要将序列对应的相对或绝对位置信息注入模型中。
基于这一目的,一个直观的想法是将位置编码设计成与词嵌入同样大小的向量维度,然后将其与词嵌入直接相加。这样可以使模型既能获取词嵌入信息,也能获取位置信息。
具体来说,位置向量的获取方式有两种:
● 通过模型训练得到。
● 根据特定公式计算得到(使用不同频率的正弦和余弦函数直接计算)。
因此,在实际操作中,模型可以设计一个可随训练更新的位置编码层,也可以直接插入一个预先计算好的位置编码矩阵。公式如下:
在这里,作者提供了一个直观展示位置编码的示例,代码如下:
通过设置单词个数max_len和维度大小d_model可以很精准地生成位置向量的图形展示,如图3-14所示。
图3-14 设置单词个数max_len和维度大小d_model
序列中任意一个位置都可以通过三角函数进行表示。其中,pos是输入序列的最大长度,i是序列中依次的各个位置,而d_model是设定的与词向量维度相同的位置编码维度,通常为768。如果将其封装为PyTorch 2.0中的固定类形式,代码如下:
这种位置编码函数的写法过于复杂,读者直接使用即可。最终将词向量矩阵和位置编码组合如图3-15所示。
图3-15 最终将词向量矩阵和位置编码组合
融合后的特征既带有词汇信息,也带有词汇在序列中的位置信息,从而能够从多个角度对特征进行表示。
从编码器输入的序列在经过一个自注意力(self-attention)层后,会传递到前馈神经网络中,这个神经网络被称为“前馈层”。这个前馈层的作用是进一步整形通过注意力层获取的整体序列向量。
本书中的解码器遵循的是Transformer架构,因此其构建参考了Transformer中解码器的设计,如图3-16所示。读者看到图后可能会感到诧异,甚至怀疑是否放错了图。然而,并没有。
图3-16 Transformer中解码器的构建
所谓前馈神经网络,实际上就是加载了激活函数的全连接层神经网络(或者使用一维卷积实现的神经网络,这点不在这里介绍)。
既然了解了前馈神经网络,其实现也很简单,代码如下:
代码本身很简单。需要提醒读者的是,在上文中,我们使用了两个全连接层来实现“前馈”操作。然而,为了减少参数数量并减轻运行负担,实际上可以使用一维卷积或“空洞卷积”(Dilated Convolution)来替代全连接层,从而实现前馈神经网络。这一优化的具体实现可以由读者自行探索完成。
在实际应用中,通过组合多层Block模块可以增强整体模型的学习与训练能力。
同样,在注意力模型中,也需要通过组合多层Block模块来增强模型的性能和泛化能力,在此可以通过将不同的模块组合在一起来完成TransformerBlock层的构建。代码如下:
可以看到,通过调用多个子层(sublayer),将不同的模块组合在一起,从而实现了可叠加使用的TransformerBlock。
通过本章前面内容的分析,我们可以看到,实现一个基于注意力架构的编码器并不困难。只需要按照架构依次将各个模块组合起来即可。接下来,作者将逐步提供代码,读者可以参考注释进行学习。
可以看到,真正实现一个编码器,从理论和架构上来说并不困难,只需要读者细心即可。