Attention Is All You Need 论文总结

论文摘要

主流的序列转换模型基于复杂的循环神经网络或卷积神经网络,这些网络包括编码器和解码器。表现最好的模型还通过注意力机制将编码器和解码器连接起来。我们提出了一种新的简单网络架构,Transformer,仅依赖注意力机制,完全去除了循环和卷积。在两个机器翻译任务上的实验表明,这些模型在质量上表现更优,同时具有更好的并行性,并且需要显著更少的训练时间。我们的模型在WMT 2014英语到德语翻译任务上取得了28.4的BLEU分数,相比现有的最佳结果(包括集成模型)提高了超过2个BLEU分。在WMT 2014英语到法语翻译任务中,我们的模型经过8个GPU、3.5天的训练后,建立了单一模型新的最先进BLEU分数41.8,这仅为文献中最佳模型训练成本的一小部分。我们还通过将Transformer成功应用于英语成分解析任务,展示了其在大数据和有限数据条件下的良好泛化能力。

论文链接:[1706.03762] Attention Is All You Need (arxiv.org)

前言

Transformer通过引入自注意力机制(Self-Attention Mechanism)和去除循环神经网络(RNN)及卷积神经网络(CNN),解决了传统序列模型在长距离依赖和并行计算上的局限性。

Embedding

因为计算机无法对一个单词或者汉字直接进行处理,所以就需要把转化成的token变成可以操作的向量,这个过程就是Embeding。

比如“我爱吃苹果”这句话经过Embeding操作之后可以变成这个样子

 每一个token都被映射到一个n维空间中,关系越相近在这个n维空间中的聚集就越近。

在学习的过程中,就是通过token之间的关系来更新token在这个n维空间中的位置。

Self Attention

Q(Query)、K(Key)、V(Value)

对于每一个token都会生成一个初始的向量,每一个向量都会通过线性变换生成三个向量,也就是Q、K、V。

假设有一个二维的token向量的值为[2, 3],下面就是Q,K,V向量的生成过程。

线性变换生成Q:将x与权重矩阵相册得到Q

Q = [2, 3] * [[1, 0], [0, 1]] = [2, 3]

线性变换生成K:将x与权重矩阵相册得到K

K = [2, 3] * [[2, 1], [1, 2]] = [7, 8]

V同上,其中Q、K和V权重矩阵是在训练过程中通过优化算法自动学习得到的。

Q向量:用于向其他的token进行查询的向量。

K向量:用于对查询进行应答的向量。

V向量:用于更新Embedding的向量。

在训练的过程中,每一个token的Q向量都会分别与其他token的K向量做点积运算(相似性匹配)。

一个token的Q分别与所有的K做点积运算后,可以组成一个相似度向量,这个向量接下来会经过softmax处理得到一个百分比向量,这个百分比分别与所有的token的V向量对应相乘,就可以得到更新后的新的token向量表示。

MultiHead Attention

在MultiHead Attention中,一个token的embedding被转化成多组完全一样的Q,K和V。在本文中使用的是8组。

具体如下所示:

 这样就能并行执行多个Attention操作

对于一个句子的多个token,在运算时会分别将每一token的Q、K、V向量组合到一起,组成三个矩阵方便计算,每一行就代表一个token的对应值。

下面是矩阵形式的计算公式:

 MultiHead

在训练的过程中不会直接将一整个embedding进行运算,而是拆分成多个Head,这就是叫做MultiHead的原因。

 这样分别进行操作的Head部分最后都会产生一个Attention(Q、K、V),这几个Attention会经过Concat操作处理,得到最终的Attention。

这样的操作应该是为了适应多显卡训练而设计的。

 def forward(self, q, k, v, mask):
        query = self.w_q(q) # (batch, seq_len, d_model) --> (batch, seq_len, d_model)
        key = self.w_k(k) # (batch, seq_len, d_model) --> (batch, seq_len, d_model)
        value = self.w_v(v) # (batch, seq_len, d_model) --> (batch, seq_len, d_model)

        # (batch, seq_len, d_model) --> (batch, seq_len, h, d_k) --> (batch, h, seq_len, d_k)
        query = query.view(query.shape[0], query.shape[1], self.h, self.d_k).transpose(1, 2)
        key = key.view(key.shape[0], key.shape[1], self.h, self.d_k).transpose(1, 2)
        value = value.view(value.shape[0], value.shape[1], self.h, self.d_k).transpose(1, 2)

        # Calculate attention
        x, self.attention_scores = MultiHeadAttentionBlock.attention(query, key, value, mask, self.dropout)
        
        # Combine all the heads together
        # (batch, h, seq_len, d_k) --> (batch, seq_len, h, d_k) --> (batch, seq_len, d_model)
        x = x.transpose(1, 2).contiguous().view(x.shape[0], -1, self.h * self.d_k)

        # Multiply by Wo
        # (batch, seq_len, d_model) --> (batch, seq_len, d_model)  
        return self.w_o(x)

 ResidualConnection

在每次经过MultiHead Attention操作之后会进行归一化,然后就使用了ResudialConnection。

class ResidualConnection(nn.Module):
    
        def __init__(self, features: int, dropout: float) -> None:
            super().__init__()
            self.dropout = nn.Dropout(dropout)
            self.norm = LayerNormalization(features)
    
        def forward(self, x, sublayer):
            return x + self.dropout(sublayer(self.norm(x)))

Feed Forward

Feed Forward由两个线性层,一个dropout组成,它的功能是增强模型的表达能力和复杂性,是模型能更好地捕捉数据中地复杂特征。

代码如下:

class FeedForwardBlock(nn.Module):

    def __init__(self, d_model: int, d_ff: int, dropout: float) -> None:
        super().__init__()
        self.linear_1 = nn.Linear(d_model, d_ff) # w1 and b1
        self.dropout = nn.Dropout(dropout)
        self.linear_2 = nn.Linear(d_ff, d_model) # w2 and b2

    def forward(self, x):
        # (batch, seq_len, d_model) --> (batch, seq_len, d_ff) --> (batch, seq_len, d_model)
        return self.linear_2(self.dropout(torch.relu(self.linear_1(x))))

整体架构

 这就是Transformer的整体架构,左侧是Encoder部分,右侧是Decoder部分。

我们都知道如果改变词语的位置,可能意思会发生很大的改变,例如“他给了我一份礼物”和“我给了他一份礼物”的意思完全不一样,但是前面的Attention机制并没有注意到位置上的信息,所以,从架构图中可以看到,Positional Encoding做的就是给Embedding加上位置信息。

Positional Encoding

在文中使用了sin和cos函数来作为位置编码。

 最后这个计算出来的位置编码与embedding本身相加作为输出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值