论文阅读——transformer:Attention is All You Need

笔记1: Attention is All You Need

阅读文献并记录,内容有些繁杂,我遇到不会的喜欢直接查直接记,所以会出现一部分的插入笔记,便于以后再看。参考的视频和文献都在最下方引用了。

Abstract

在自然语言处理领域,占据主导地位的序列转换模型是包含编码器和解码器结构的RNN或者CNN网络。其中表现最好的模型是通过注意力机制连接的一个编码器-解码器结构。本文提出一个简单的网络结构,Transformer模型,仅仅由注意力机制构成,没有使用循环和卷积

Instruction

RNN(循环神经网络)是进行序列建模的主要模型。
RNN的特点:从左往右一步步的移动,无法进行并行处理,必须等待前面的运行完。
注意力机制:已经成为各种网络中重要的一部分。目前各种任务为了能够关注到其中的感兴趣部分,经常加入注意力机制进行改进。
在这项工作中,本文提出了 Transformer,这是一种避免使用循环结构,而是完全依赖注意力机制来绘制输入和输出之间的全局依赖关系。

Background

为了减少时序计算,一般是使用卷积神经网络作为基本构建块(如ByteNet [18] and ConvS2S [9],使用卷积神经网络代替循环神经网络减少时序计算)。
但是使用卷积神经网络难以对长序列进行建模。这是因为卷积神经网络每一次只会看一个小窗口。(比如说,看一个3x3的像素块,如果两个像素块离的比较远,需要用很多层卷积一层一层的处理才能够将两个隔得很远的像素给融合起来)
但是如果我们选择注意力机制,则能看到所有的序列。
但是CNN有一个优点,可以做多个输出通道。一个输出通道可以认为他是可以去识别不一样的模式,所以transformer也想要这种多通道的效果,所以提出使用了Multi- Head Attention。
自注意力机制(self-attention):是一种将单个序列的不同位置关联起来,计算序列的注意力机制。

Model Structure

总体来说包含两个部分,分别为编码器解码器
核心模块为:自注意力机制
transformer的核心结构是self- attention。但是仅有自注意力模块是不够的。因为自注意力机制在运算的过程中仅与内容有关系,和位置信息无关。但是在语言建模中,词和词的相对位置很重要。

除了自注意力机制,还有:
(1)位置信息
(2)层规范化
(3)残差连接
(4)位置前馈网络(也可以理解为窗口为1的卷积)

Encoder-Decoder

编码器:输入为两个部分:输入句子序列+词在句子中的位置信息。然后进入编码器的主体部分(图中左半部分编码器的灰色框)。输入部分首先经过自注意力机制(如标注图中红色线所示)进行多头自注意力的学习,然后使用Norm层进行处理。同时,该部分通过一个残差结构进行连接(如标注图中的粉红色线所示)。然后在进入前馈网络和一个Norm层(也就是一个MLP),同时该部分也用一个残差结构连接。
这两个部分组成了一个编码器的transformer block,Nx表示多个block进行叠加。一个block中包含一个Multi-Head Attention(多头注意力机制)
简单概括
在本文中encoder使用了6个block,每个block包含两个子层,一个是多头自注意力机制,另一个是前馈网络。在每个子层中使用残差连接。
此处的Norm使用的是LayerNorm。(batch norm 和 layer norm的区别)使用layer norm能够使网络更加的稳定。
维度dmodel=512

解码器:对于解码器的输入而言,首先第一部分的输入为解码器之前做出的输出+位置信息。然后通过Mask Multi head Attention和一个Norm层+残差结构。然后进入第二个部分,该部分的输入不仅仅是第一个部分的输出,还要加上编码器的block的输出作为自注意力机制所需的K、V、Q的值(假设,K、V来自于编码器的输出、Q来自于解码器第一部分的输出)。这些输入进入Multi-Head Attention和Norm层+一个残差连接进行处理。接着进入第三个部分进入前馈网络和一个Norm层,同时该部分也用一个残差结构连接。最后通过第四部分,一个linear层和一个softmax层进行预测,输出结果。
(插入笔记:解码器是一个自回归模型,他只能前面有什么,他看到什么,不像encoder,可以都能看到。比如说如下图,在decoder生成“机”的时候,只能看到左边encoder的内容和“$”的符号。产生“机”后作为下一个输入,产生“器”。也是一个典型的序列到序列模型的典型架构。
整体同时输入“Machine Learning”和Decoder部分右移的输出,来预测下一个词。)
复旦邱老师笔记

简单概括:decoder也使用了6个block。不同于编码器有两个子层,解码器加入了第三个子层(对编码器堆栈的输出执行多头注意力),同时每个子层都会用残差连接。同时对第一个子层的自注意力结构进行了更改(加入mask,带掩码的自注意力机制),在t时间不会看到t时间以后的输入,保证训练和预测时候的行为是一致的。

transformer模型结构图
transformer总结的整体结构图

transformer原结构图
加入标注的transformer模型结构图
加入自己理解的Transformer结构图

Self- Attention

自注意力函数可以描述为:将查询值(Q,query)和一组键值对(K- V,key-value,相当于数据库中,k为索引,v为对应的值)映射到输出,其中Q、K、V和ouput都是向量。
其实可以这样理解。Q是我们的目标值(要查询的信息),K是索引(我们需要查看的东西),V是K的值(查询到的值),为了寻找K中与Q最接近的部分,我们计算K和Q的相似度作为一个权重(概率p),然后作用在V值上(与V相乘)。也就是将最相似的值赋予大的权重,遮掩掉不相关的部分。最后将赋予权重后的V加起来(加权合成),得到输出结果。
在这里,为求相似度,不同的相似度有不同的计算方式。
本文中使用的是多头自注意力。其中,在多头自注意力结构中,使用了一个最基本的注意力机制,点积注意力(scaled dot- product attention)。

(插入笔记:普通的注意力机制数学表示。x1,x2,…,xn,为接入向量。查询向量q(任务相关向量)。我们的目的是从这些候选信息中只查询与任务相关的信息。首先第一步计算注意力分布a:对q和xn做内积得到相似度。由于这个相似度分数大小不一,进行归一化处理。通过归一化处理后,就得到了a1,a2,…,an,加起来,和为1。也就是进行了权重的分配。有了分布之后,对每一个信息进行加权。从而得到了注意力。阿尔法是一个分布,我们也可以理解是对分布做了一个期望。)
复旦邱老师笔记
(插入笔记:例子。如果要查与The的匹配程度,将五个词分别做内积后并进行归一化处理,得到五个参数。然后对参数加权求和,得到结果。其中,查询向量来自内部模式,这种就叫做自注意力。)
复旦邱老师笔记

(插入笔记:自注意力的Q,K,V从哪里来的? 原始的自注意力机制,一般是一个词既当目标query,又当候选信息来用,输入为一个向量。且他不带参数,不带参数,模型的容量会非常小。全用X 最大的问题可能是: 自身对自身的attention score太大, 挤压了其他attention score。为了提高自注意力模型的能力。在实际使用中,会使用一个变体,也就是QKV模式。对一个输入X,有N个词,维度是Dx,分别给三个可训练的参数矩阵,与X相乘,相当于经历了一次线性变换。Attention不直接使用X,而是使用经过矩阵乘法生成的这三个矩阵,因为使用三个可训练的参数矩阵,可增强模型的拟合能力。图中Q每一行是一个词。)
复旦邱老师笔记

Scaled Dot-Product Attention
本文中的注意力机制使用的QKV模式的自注意力机制。首先计算需要查询的值Q与候选值K之间的相似度分数,这里用内积来计算。(余弦相似性其实是内积的归一化。余弦相似度原理,内积为1,两条直线重合,相似度最大;内积为0,两条直线垂直,相似度最小。)然后对相似度分数开方。开方的原因,有的分数大,有的分数小,会使得整体分布sharp,不利于在神经网络中进行梯度的回传,所以在使用过程中开方,使得分布比较平缓。开方的值为根号下dk,dk为k的维度大小。这个除法被称为Scale。当dk很大时,相似度矩阵的乘法结果方差变大,进行Scale可以使方差变小,训练时梯度更新更稳定。接着对其进行softmax归一化处理,得到每个值的权重,最后与V加权求和,得到最后的结果。
在这里插入图片描述
在这里插入图片描述

Multi-Head Attention
第二个图,邱老师画的图会更直观一些。就是做了多次映射(图中做了三次映射),在不同的映射中Q,K,V都不一样,不是共享的。每次映射是在某一空间中建立语义交互关系。比较像卷积中的多通道概念,我们会得到不同通道的feature map。然后将每次映射后经过Scaled Dot-Product Attention得到的结果组合拼接,然后通过一个参数矩阵,再映射回原来的维度。
在这个过程中,不同的映射,就称为不同的head。且是多个head同时进行。
为什么我们要做多头注意力机制,可以参考2021-11-28 沐神《transformer论文逐段精读》
论文中的多头注意力
复旦大学邱锡鹏教授讲解

Mask Multi head Attention
就是加了一个mask掩码,在实际做的过程中,数据是一起输进去的。为了每个词能够看见他之前的输入,使用了掩码机制。

Applications of Attention

1、在解码器的第二个部分,输入为解码器的输出Q和编码器的输出K,V
2、在编码器的自注意力机制中,使用QKV模式的自注意力机制,其中QKV都来自于一个输入
3、在解码器的第一个部分,使用了掩码的方式只关注每个词之前的输入

Position-wise Feed-Forward Networks

一个简单的全连接网络,该网络由两个线性变换组成,中间有一个 ReLU 激活函数。虽然线性变换在不同位置上是相同的,但它们在层与层之间使用不同的参数。另一种描述方式是内核大小为 1 的两个卷积。

Embeddings and Softmax

embedding是一个向量,是将input tocken和output tocken 变成向量。
(插入笔记:假设{“我” “爱” “你”}这个列表是tokenization(分词),列表中的每一个元素代表一个token。可以分解成以字词(token) 为单位的数据结构。如何将一个词变成一个向量?embedding一下就好。如果有两个词,[0 1]为第一个词,[1 0]为第二个词,当然有更好的编码方式,在这里只是简单的理解一下。)
softmax,在注意力机制中,进行概率预测。

Positional Encoding

由于模型不包含递归和卷积,为了让模型利用序列的顺序,必须注入一些关于序列的相对或绝对位置的信息。为此,在编码器和解码器堆栈底部的输入嵌入中添加“位置编码”。位置编码与嵌入具有相同的维度 dmodel,因此可以将两者相加。本文使用不同频率的正弦和余弦函数进行编码。
论文编码公式

其中 pos 是位置,i 是维度。也就是说,位置编码的每个维度对应一个正弦曲线。波长形成从 2π 到 10000 · 2π 的几何级数。

Transformer优点和缺点

优点:
(1)并行化。
(2)不需要堆叠很多层就能找到非局部的依赖关系。
缺点:
(1)当句子很长时,复杂度会很高。

网络特性对比

卷积神经网络
1、平移不变性
2、局部性

循环神经网络
1、时间维上共享参数
2、局部性

Transformer
1、无结构先验信息,容易在小数据集上过拟合
2、加入位置编码,额外建模位置信息

注意力模块代码

Attention

def attention(query, key, value, mask=None, dropout=None):
    "Compute 'Scaled Dot Product Attention'"
    d_k = query.size(-1)
    scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)  # comparison scores
    if mask is not None:
        scores = scores.masked_fill(mask == 0, -1e9)  # check defined mask, assign very low value to mask
    p_attn = scores.softmax(dim=-1)  # softmax on row
    if dropout is not None:
        p_attn = dropout(p_attn)
    return torch.matmul(p_attn, value), p_attn
class MultiHeadedAttention(nn.Module):
    def __init__(self, h, d_model, dropout=0.1):
        "Take in model size and number of heads."
        super(MultiHeadedAttention, self).__init__()
        assert d_model % h == 0
        # We assume d_v always equals d_k
        self.d_k = d_model // h  # d_model=512, d_k=d_v=d_model//h=64 
        self.h = h
        self.linears = clones(nn.Linear(d_model, d_model), 4)
        self.attn = None
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, query, key, value, mask=None):
        "Implements Figure 2"
        if mask is not None:
            # Same mask applied to all h heads.
            mask = mask.unsqueeze(1)
        nbatches = query.size(0)

        # 1) Do all the linear projections in batch from d_model => h x d_k
        query, key, value = [
            lin(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2)
            for lin, x in zip(self.linears, (query, key, value))
        ]  # 3 linear layers used here
        # e.g. query = (30,10,512) -> linear layer -> (30,10,512) -> view 
        # -> (30,10,8,64) -> transpose(1,2) -> (30,8,10,64)

        # 2) Apply attention on all the projected vectors in batch.
        x, self.attn = attention(
            query, key, value, mask=mask, dropout=self.dropout
        )

        # 3) "Concat" using a view and apply a final linear.
        x = (
            x.transpose(1, 2)
            .contiguous()
            .view(nbatches, -1, self.h * self.d_k)
        )
        # x = (30,8,10,64) -> transpose(1,2) -> (30,10,8,64) -> contiguous and view
        # -> (30,10,8*64) -> (30,10,512)

        del query
        del key
        del value
        return self.linears[-1](x)  # 4th linear layer

后续会再更一下邱老师对于改进方面的笔记,感觉很受启发。

参考链接

1、沐神视频讲解
2、原文
3、复旦大学邱锡鹏教授讲解
4、知乎参考:注意力机制到底在做什么,Q/K/V怎么来的?一文读懂Attention注意力机制
5、NLP中什么是span和token

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值