深度学习:transformer模型-程序员宅基地

技术标签: NLP  深度学习DeepLearning  深度学习  transformer  

        Google于2017年6月发布在arxiv上的一篇文章《Attention is all you need》,提出解决sequence to sequence问题的transformer模型,用全attention的结构代替了lstm,抛弃了之前传统的encoder-decoder模型必须结合cnn或者rnn的固有模式,只用attention。文章的主要目的是在减少计算量和提高并行效率的同时不损害最终的实验结果,创新之处在于提出了两个新的Attention机制,分别叫做 Scaled Dot-Product Attention 和 Multi-Head Attention。

        考虑到RNN(或者LSTM、GRU等)的计算限制是顺序的,也就是说RNN相关算法只能从左向右依次计算或者从右向左依次计算,这种机制带来了两个问题:1 时间片t的计算依赖t-1时刻的计算结果,这样限制了模型的并行能力;2 顺序计算的过程中信息会丢失,尽管LSTM等门机制的结构一定程度上缓解了长期依赖的问题,但是对于特别长期的依赖现象,LSTM依旧无能为力。

transformer模型结构

        论文中的验证Transformer的实验室基于机器翻译的,其本质上是一个Encoder-Decoder的结构,编码器由6个编码block组成(encoder每个block由self-attention,FFNN组成),同样解码器是6个解码block组成(decoder每个block由self-attention,encoder-decoder attention以及FFNN组成),与所有的生成模型相同的是,编码器的输出会作为解码器的输入。Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence aligned RNNs or convolution。

Transformer可概括为:

所有的编码器在结构上都是相同的,但它们没有共享参数。 

具体模型结构如下图:

illustration from Lin et al,, "A Survey of Transformers"比原文图好看

Note:这里需要说明一下,原始transformer中的隐层向量维度hidden_size=d_model=512,multihead个数n_head=8;而bert中hidden_size=d_model=768,multihead个数n_head=12。

Transformer Encoder

        Encoder由Nx个相同的layer组成,layer指的就是上图左侧的单元,最左边有个“Nx”(论文中是6个)。每个Layer由两个sub-layer组成,分别是multi-head self-attention mechanism和fully connected feed-forward network。

其中每个sub-layer都加了residual connection和normalization,即在两个子层中会使用一个残差连接,接着进行层标准化(layer normalization)。因此可以将sub-layer的输出表示为: 

bert里面实现时的一般结构

BertLayer
    BertAttention
        BertSelfAttention(即去除最后那个linear后的multi-head)
        BertSelfOutput(multi-head最后那个linear + dropout + LN)
    BertIntermediate
        FNN的前一半nn.Linear(hidden_dim, intermediate_dim) + 激活
    BertOutput
        FNN的后一半(nn.Linear(intermediate_dim, hidden_dim))linear + dropout + LN

绘成图就是这样:[Bert 主体模型]

多头注意力Multi-head attention:Models context

即加了最后那个linear层后的multi-head

        一句话概括做了啥:attention就是将每个word的词向量,通过seq中其它词的加权来表示。

        Transformer所使用的注意力机制的核心思想(也是注意力机制有效的解释)是去计算一句话中的每个词对于这句话中所有词的相互关系,然后认为这些词与词之间的相互关系在一定程度上反应了这句话中不同词之间的关联性以及重要程度,因此再利用这些相互关系来调整每个词的重要性(权重)就可以获得每个词新的表达,这个新的表征不但蕴含了该词本身,还蕴含了其他词与这个词的关系,因此和单纯的词向量相比是一个更加全局的表达。使用了Attention机制,将序列中的任意两个位置之间的距离缩小为一个常量,Attention层能够一步到位捕捉到全局的联系,因为它直接把序列两两比较(代价是计算量变为(n^2),当然由于是纯矩阵运算,这个计算量相当也不是很严重);相比之下,RNN需要一步步递推才能捕捉到,而CNN则需要通过层叠来扩大感受野,这是Attention层的明显优势。

Multi-head attention:论文提出对queries,keys和values做h次不同的投影(linear)到一个低维(从d_model维度映射到d_k或者d_v维度);然后做h(=d_model/d_k)次scaled dot-product attention,得到h个输出,将这些输出变量concat(回到d_model维度)。最后做一次线性的投影得到最终的输出(具体实现时,一般这个linear不当作attention实现的一部分,而是当成output的一部分)。

 

在最后,如multi-head attention图,在最后乘上一个768*768的线性层。

Transformer会在三个地方使用multi-head attention:

        encoder self-attention:输入的Q、K、V都是encoder的input embedding and positional embedding。
        decoder self-attention:在decoder的self-attention层中,deocder 都能够访问当前位置前面的位置(shifted right),输入的Q、K、V都是decoder的input embedding and positional embedding。

        encoder-decoder attention:输入为encoder的输出和decoder的self-attention输出,其中encoder的self-attention作为 key and value,decoder的self-attention作为query。

Note:

1 在一般的attention模型中,Q就是decoder的隐层,K就是encoder的隐层,V也是encoder的隐层。所谓的self-attention就是取Q,K,V相同,均为encoder或者decoder的input embedding and positional embedding。

2 attention线性变换的计算采用了scaled dot-product attention:即上面公式1

点乘注意力的升级版本[深度学习:注意力模型Attention Model:Self Attention]

其中d_k (size_per_head=attention_head_size=hidden_size / num_attention_heads=768/12(bert)=512/8(trans)=64:  Size of each attention head)即转换后的Q/K/V词向量维度,也是attention转换后的词向量维度。

        作者同样提到了另一种复杂度相似的计算方法additive attention,在 d_k很小的时候和dot-product结果相似,d_k大的时候,相对不进行缩放的dot-product表现更好。但dot-product的计算速度更快,进行缩放后可减少影响,点乘注意力机制对于加法注意力而言,更快,同时更节省空间。

        transformer中的attention为什么scaled? 向量的点积结果如果很大,会将softmax函数push到梯度很小的区域,scaled会缓解这种现象。即比较大的输入会使得softmax的梯度变得很小,类比sigmoid饱和区;为什么使用维度的根号来放缩?假设向量 q 和 k 的各个分量是互相独立的随机变量,均值是0,方差是1,那么点积 q*k 的均值是0,方差是 d_k ,将方差控制为1,也就有效地控制了前面提到的梯度消失的问题,类比distill中的温度[transformer中的attention为什么scaled?]。也可以不除以√d,但是初始化q,k的全连接层的时候,其初始化方差要多除以一个√d,这同样能使得使q⋅k的初始方差变为1,T5采用了这样的做法。[浅谈Transformer的初始化、参数化与标准化]

3 softmax后可以再加个dropout,然后再multiply V。

4 同时要保持词向量embedding大小在经过多头注意力后不变(经过linear后的维度也不变),W^Q的维度应该是d_model*d_k = hidden_size*(hidden_size/num_attention_heads) = 512*64(trans)=768*64(bert),这样得到num_attention_heads(=d_model/d_k)个attention后的seq_len*(hidden_size/num_attention_heads=64) 维向量按列拼接(即*num_attention_heads),就得到seq_len*hidden_size大小的向量。

5 虽然说的是多头,但是在实现时实际是通过transposes and reshapes tensors实现的,而不是分开的tensors。即先将输入query_layer和key_layer (batch_size, seq_len, hidden_size)转成(batch_size, seq_len, num_attention_heads, attention_head_size),再转换成(batch_size, num_attention_heads, seq_len, attention_head_size)。然后计算attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2))。

6 不考虑多头的原因,self-attention中词向量不乘QKV参数矩阵,会怎么样?  sequence中的每个词都会和sequence中的每个词做点积去计算相似度,也包括这个词本身。在相同量级的情况下,qi与ki点积的值会是最大的。那在softmax后的加权平均中,该词本身所占的比重将会是最大的,使得其他词的比重很少,无法有效利用上下文信息来增强当前词的语义表示。而乘以QKV参数矩阵,会使得每个词的q,k,v都不一样,能很大程度上减轻上述的影响。

7 Multi-Head效果的尝试解释:原论文中说,将模型分为多个头,形成多个子空间,可以让模型去关注不同方面的信息。有大量的paper表明,Transformer,或Bert的特定层是有独特的功能的,底层更偏向于关注语法,顶层更偏向于关注语义。如果要说不同的头关注的方面不一样,但同一层中的多数头的关注模式是一样的(比如第3层的1234头);如果说一样吧,又总有那么一两个头与众不同。Multi-Head其实不是必须的,去掉一些头效果依然有不错的效果(而且效果下降可能是因为参数量下降),这是因为在头足够的情况下,这些头已经能够有关注位置信息、关注语法信息、关注罕见词的能力了,再多一些头,无非是一种enhance或noise而已。    另外,头之间的方差随着所在层数的增大而减小。初始化对Transformer的影响[https://arxiv.org/pdf/1908.11365.pdf]讨论了初始化对Transformer各层方差的影响,最终缓解梯度消失的问题。从这个角度讲,Transformer底层的头方差大是因为Transformer存在的梯度消失问题,也就是说,并不是模型自己觉得底层的方差大是好的,而是自己没有办法让它变好。所以,合理的初始化应该可以减少底层头的方差,提高效果。这种差距有什么作用至今还没有得到解释。一种可能的解释是,它类似一种noise,或者dropout,而不是去关注不同的方面。也就是说,无论多少层,既然都会出现与众不同的头,那么这个(些)头就是去使得模型收敛(效果最优)的结果,反过来说,模型可能认为,全部一样的头不会使效果最优(至少在梯度下降的方法上)。这样的话,把这个(些)头解释为模型的一种“试探”,或者噪声,是可能合理的。[为什么Transformer 需要进行 Multi-head Attention?] 在不增加时间复杂度的情况下,同时,借鉴CNN多核的思想,在更低的维度,在多个独立的特征空间,更容易学习到更丰富的特征信息。[transformer中multi-head attention中每个head为什么要进行降维?]

Position-wise feed-forward networks:Computes non-linear hierarchical features

即Intermediate和Output层。 

        位置全链接前馈网络——MLP变形。之所以是position-wise是因为处理的attention输出是某一个位置i的attention输出,或者说之所以是position-wise是因为过线性层时每个位置i的变换参数是一样的。每个位置的单词对应的前馈神经网络都完全一样(译注:另一种解读就是一层窗口为一个单词的一维卷积神经网络)或者说参数是共享的。
        其实就是一个MLP 网络,每个 d_model 维向量 x 在此先由 xW_1+b_1 变为 d_ff=2048 维的 x',再经过max(0,x')W_2+b_2 回归 d_model 维。

        Feed Forward Neural Network全连接有两层dense,第一层的激活函数是ReLU(或者其更平滑的版本Gaussian Error Linear Unit-gelu),第二层是一个线性激活函数,如果multi-head输出表示为Z,则FFN可以表示为:

   (2)

Note: hidden_size变化为:768->3072->768(bert)或者512->2048->512(trans)。W1维度hidden_size*(4*hidden_size),W2维度(4*hidden_size)*hidden_size。Bert沿用了惯用的全连接层大小设置,即4 * hidden_size。

Layer norm and residuals:Makes training deep networks healthy

        之后就是对hidden层进行dropout(dropout率为0.1,也就是把输出的10%的那些元素值乘0.1,剩下的值乘1.1),最后加一个resnet并normalization(tensor的最后一维)。

self.layer_norm = nn.LayerNorm(d_model, eps=1e-6)

Note: 这里进行的是layer norm,是对最后一维d_model进行LN,而不是max_seq_len*d_model进行LN,即是对token embedding进行LN而不是对句子进行LN。各个样本(句子)的各个时间步(词)有自己的均值和标准差,并且weight和bias的维度也都是(768,),只是后面可能每步weight和bias变化不大时,可近似看成句子。

[深度学习:批归一化和层归一化][Bert、Transformer中为何使用的是LN而很少使用BN

Transformer通过对输入的文本不断进行这样的注意力机制层和普通的非线性层交叠来得到最终的文本表达。

Transformer Decoder

Decoder和Encoder的结构差不多,但是多了一个attention的sub-layer。

训练时:

 对应上图先明确一下decoder的输入输出和解码过程:

  • 输出:对应i位置的输出词的概率分布。
  • 输入:encoder的输出 & 对应i-1位置decoder的输出(所以最开始的attention是self-attention(QKV全是decoder隐层);中间的attention不是self-attention,K,V来自encoder,Q来自上一位置decoder的输出)。
  • 解码:编码可以并行计算,一次性全部encoding出来,但解码不是一次把所有序列解出来的,而是像rnn一样一个一个解出来的,因为要用上一个位置的输入当作attention的query。

        decoder中间的Multi-head attention(Encoder-Decnoder Attention)和Position-wise feed-forward networks同encoder。不同的是decoder第一个多头注意力子层(Self-Attention)是当前翻译和已经翻译的前文之间的关系;Encoder-Decoder Attention是当前翻译和编码的特征向量之间的关系。

Masked multi-head attention:对于decoder中的第一个多头注意力子层,需要添加masking,确保预测位置i的时候仅仅依赖于位置小于i的输出,确保预测第i个位置时不会接触到未来的信息。在机器翻译中,解码过程是一个顺序操作的过程,也就是当解码第i个特征向量时,我们只能看到第i-1及其之前的解码结果。而我们要计算的attention是根据当前词i和前面的词来的,不能是后面的。

Positional Encoding:learn relative positioning

        截止目前为止,Transformer模型并没有捕捉顺序序列的能力,也就是说无论句子的结构怎么打乱,Transformer都会得到类似的结果,只是一个功能更强大的词袋模型而已。所以作者提出两种Positional Encoding的方法,将Positional Encoding后的数据与输入embedding数据求和,加入了相对位置信息。

怎么实现位置编码?

      一种做法就是分配一个0到1之间的数值给每个时间步,其中,0表示第一个词,1表示最后一个词。这种方法虽然简单,但会带来很多问题。其中一个就是你无法知道在一个特定区间范围内到底存在多少个单词。换句话说,不同句子之间的时间步差值没有任何的意义。

      另一种做法就是线性分配一个数值给每个时间步。也就是,1分配给第一个词,2分配给第二个词,以此类推。这种方法带来的问题是,不仅这些数值会变得非常大,而且模型也会遇到一些比训练中的所有句子都要长的句子。此外,数据集中不一定在所有数值上都会包含相对应长度的句子,也就是模型很有可能没有看到过任何一个这样的长度的样本句子,这会严重影响模型的泛化能力。

因此,一种好的位置编码方案需要满足以下几条要求:

  • 它能为每个时间步输出一个独一无二的编码;
  • 不同长度的句子之间,任何两个时间步之间的距离应该保持一致;
  • 模型应该能毫不费力地泛化到更长的句子。它的值应该是有界的;
  • 它必须是确定性的。

Transformer的作者们提出了一个简单但非常创新的位置编码方法,能够满足上述所有的要求。首先,这种编码不是单一的一个数值,而是包含句子中特定位置信息的d维向量(非常像词向量)。第二,这种编码没有整合进模型,而是用这个向量让每个词具有它在句子中的位置的信息。换句话说,通过注入词的顺序信息来增强模型输入。

两种Positional Encoding方法:

  1. 用不同频率的sine和cosine函数直接计算
  2. 学习出一份positional embedding(参考文献)。学习时注意,每个batch的pos emb都一样,即在batch维度进行broadcast。

经过实验发现两者的结果一样,所以最后选择了第一种方法,并且如果是不学习的,后面可以处理更长的句子(We chose the sinusoidal version because it may allow the model to extrapolate to sequence lengths longer than the ones encountered during training.)。公式如下:

其中pos 表示单词的位置, i 表示单词的维度,d_model表示位置向量维度=embedding维度=512(trans)或者768(bert)。

Note:

1 关于位置编码的实现可在Google开源的算法中get_timing_signal_1d()函数找到对应的代码。

2 从函数定义中可以得出,频率沿向量维度减小。因此,它在波长上形成从2pi到1000*2pi几何级数。你也可以认为,位置编码是一个包含每个频率的正弦和余弦对(注意d是能被2整除的)。

3 方法1的好处有两点:1. 任意位置的 PE_(pos+k) 都可以被 PE_pos 的线性函数表示。考虑到在NLP任务中,除了单词的绝对位置,单词的相对位置也非常重要。根据公式 sin(a+b)=sina*cosb+cosa*sinb 以及 cos(a+b)=cosa*cosb-sina*sinb,这表明位置 k+p 的位置向量可以表示为位置 k 的特征向量的线性变化,这为模型捕捉单词之间的相对位置关系提供了非常大的便利。2. 如果是学习到的positional embedding,可能会像词向量一样受限于词典大小。也就是只能学习到“位置2对应的向量是(1,1,1,2)”这样的表示。所以用三角公式明显不受序列长度的限制,也就是可以对 比所遇到序列的更长的序列 进行表示。

在后面我们可以看到,旋转式位置编码正好利用了矩阵 R_k 的这种性质。

[六种位置编码的代码实现及性能实验 - 知乎]

示例:位置t的单词的位置向量计算

[一文读懂Transformer模型的位置编码]

[Transformer Architecture: The Positional Encoding]

[BERT的三个Embedding直接相加会对语义有影响吗?]

Note: transformer无法对位置信息进行很好地建模,这是硬伤。尽管可以引入Position Embedding,但我认为这只是一个缓解方案,并没有根本解决问题。举个例子,用这种纯Attention机制训练一个文本分类模型或者是机器翻译模型,效果应该都还不错,但是用来训练一个序列标注模型(分词、实体识别等),效果就不怎么好了。那为什么在机器翻译任务上好?我觉得原因是机器翻译这个任务并不特别强调语序,因此Position Embedding所带来的位置信息已经足够了,此外翻译任务的评测指标BLEU也并不特别强调语序。

词嵌入再加上position encoding的时候,也用了一个dropout。也就是说,基本上对于每一个带权重的层,在输出上都使用了dropout,虽然dropout率不是特别高,但是使用了大量的dropout层来对模型做正则化。

其它的位置编码方法

旋转式位置编码 RoPE

假设一个函数f()通过他能让q,k带上位置m,n的绝对位置信息
q = f(q, m), k = f(k, n)
通过内积后,希望结果带上相对位置信息,因此假设存在下列恒等关系
<f(q,m), f(k,n)> = g(q,k,m-n)

假设 f(., t) 的形式为 R_t*x ,那么有

[RoPE(旋转式位置编码)_世界划水锦标赛冠军的博客-程序员宅基地]

[六种位置编码的代码实现及性能实验 - 知乎]

和transfomer里面原始的三角位置编码的区别
在于它们如何为每个元素分配唯一的位置编码。
旋转式位置编码:将每个位置编码表示为一个向量,并将该向量与一个可学习的旋转矩阵相乘,以获得该位置的最终编码。这种方法可以保证每个位置都有一个唯一的编码,并且可以通过学习旋转矩阵来适应不同的任务。
三角形位置编码:将每个位置编码表示为一个三角函数的值,其中每个函数都具有不同的频率。这种方法可以保证每个位置都有一个唯一的编码,并且可以通过调整函数的频率来适应不同的序列长度。[monica]

损失层

解码器解码之后,解码的特征向量经过一层激活函数为softmax的全连接层之后得到反映每个单词概率的输出向量。此时我们便可以通过CTC等损失函数训练模型了。

Transformer模型的评价

 优点

作者主要讲了以下三点:

1. Total computational complexity per layer (每层计算复杂度)

2. Amount of computation that can be parallelized, as mesured by the minimum number of sequential operations required

作者用最小的序列化运算来测量可以被并行化的计算。也就是说对于某个序列x1,x2,...,xn ,self-attention可以直接计算 xi,xj 的点乘结果,而rnn就必须按照顺序从 x1 计算到 xn

3. Path length between long-range dependencies in the network

这里Path length指的是要计算一个序列长度为n的信息要经过的路径长度。cnn需要增加卷积层数来扩大视野,rnn需要从1到n逐个进行计算,而self-attention只需要一步矩阵计算就可以,Transformer 在结构上优越,任何两个 token 可以无视距离直接互通。所以也可以看出,self-attention可以比rnn更好地解决长时依赖问题。当然如果计算量太大,比如序列长度n>序列维度d这种情况,也可以用窗口限制self-attention的计算数量。

4. 另外,从作者在附录中给出的栗子可以看出,self-attention模型更可解释,attention结果的分布表明了该模型学习到了一些语法和语义信息

缺点

缺点在原文中没有提到,是后来在Universal Transformers中指出的,在这里加一下吧,主要是两点:

  1. 实践上:有些rnn轻易可以解决的问题transformer没做到,比如复制string,尤其是碰到比训练时的sequence更长的时。
  2. 理论上:transformers非computationally universal(图灵完备),这种非RNN式的模型是非图灵完备的,无法单独完成NLP中推理、决策等计算问题(包括使用transformer的bert模型等等)。

和rnn/cnn比较

狭义Transformer指Attention is all you need那个结构,包含一个encoder一个decoder;广义Transformer指self-attention机制的各种应用。

1。 狭义Transformer在大数据的情况下超过RNN一点问题没有,而且是显著的超,目前在很多大数据任务都验证了,比如WMT数据集的机器翻译,BERT,以及最近的TTS。

2。狭义的Transformer在跑中等数据集(一百万)或者小数据(几万或者几千)和RNN谁好谁坏不一定,可能靠调,不是那种一个默认参数就会比RNN好,我简单的跑过中等数据集的对话(Twitter)和摘要(CNN DailyMail),感觉没好多少。小数据反而更容易过拟合,按照一些paper报的结果反而RNN好

3。广义的Transformer又是另一个故事了,我个人理解self attention机制几乎在所有任务上好好调都有用,比如分类,阅读理解(QANet),小规模s2s(Universal Transformer)。比如QAnet和Universal Transformer大家如果有兴趣可以看一看,通过自己的Recurrent机制,能给性能带来很大的增益。Multi head attention和简单的Self attention都是很有用的结构上的trick

4。ACL的哪篇文章做过一个实验。RNN对于50个词之前的词顺序就不敏感了,而对于100个词之前的就完全忘了,所以RNN在长序列上肯定是有问题的。不过Transformer的位置信息只靠Position Embedding,也有提升空间。

[有了Transformer框架后是不是RNN完全可以废弃了?]

[放弃幻想,全面拥抱Transformer:自然语言处理三大特征抽取器(CNN/RNN/TF)比较]

参数量分析

6层的encoder和decoder,参考下12层的bert

[深度学习:BERT模型_supervised fine-tuning_-柚子皮-的博客-程序员宅基地]

-柚子皮-

Transformer结构细节和实现

总结:一个2 层编码-解码结构的transformer

输入编码

Transformer的输入数据。

首先通过Word2Vec等词嵌入方法将输入语料转化成特征向量,论文中使用的词嵌入的维度为 d_model=512(trans) 或者768(bert)。

                                    单词的输入编码

在最底层的block中, x 将直接作为Transformer的输入,而其他层输入则是上一个block的输出。

                            输入编码作为一个tensor输入到encoder中

Self-Attention(scaled dot-product attention)

回想Bahdanau等人提出的用Attention,其核心内容是为输入向量的每个单词学习一个权重,例如下面例子中我们判断it代指的内容。

The animal didn't cross the street because it was too tired

通过加权之后可以得到类似下图的加权情况,在讲解self-attention的时候我们也会使用类似的表示方式

               经典Attention可视化示例图

在self-attention中,每个单词有3个不同的向量:Query向量( Q ),Key向量( K)和Value向量( V ),长度均是64,由嵌入向量 X 乘以三个不同的权值矩阵 W^Q , W^K , W^V 得到,其中三个矩阵的尺寸均是 d_model*(d_model/head_num)=512*64 。

                            Q,K,V的计算示例图

那么Query,Key,Value是什么意思呢?它们在Attention的计算中扮演着什么角色呢?我们先看一下Attention的计算方法,整个过程可以分成7步:

  1. 如上文,将输入单词转化成嵌入向量;
  2. 根据嵌入向量得到 q , k , v 三个向量;
  3. 为每个向量计算一个score: score=q*k ;
  4. 为了梯度的稳定,Transformer使用了score归一化,即除以 sqrt(q_k) ;
  5. 对score施以softmax激活函数;
  6. softmax点乘Value值 v ,得到加权的每个输入向量的评分 v ;
  7. 相加之后得到最终的输出结果 z : z=sum(v) 。

上面步骤的可以表示:

             Self-Attention计算示例图

实际计算过程中是采用基于矩阵的计算方式,那么论文中的 Q , V , K 的计算方式如:

        Q,V,K的矩阵表示:[n, e] * [e, d^q] = [n, d^q]    其中n表示当前输入的batch个句子的最大词个数(max_seq_len=512),e表示词embedding维度,d^q/d^k/d^v都表示输出维度。

总结为下面的矩阵形式:

   

              Self-Attention的矩阵表示:([n, d^q] *[d^k, n] ) * [n, d^v] = [n, d^v]

这里本质就是将某个word的词向量,通过seq中其它词的加权来表示。

Multi-Head Attention

Multi-Head Attention相当于 h 个不同的self-attention的集成(ensemble),在这里我们以 h=8 举例说明。Multi-Head Attention的输出分成3步:

  1. 将数据 X 分别输入到上面的8个self-attention中,得到8个加权后的特征矩阵 Z_i, i in {1,2,...,8} 。
  2. 将8个 Z_i 按列拼成一个大的特征矩阵(即将num_attention_heads个seq_len*(hidden_size/num_attention_heads)的向量拼接成seq_len*hidden_size的向量);
  3. 特征矩阵经过一层全连接后得到输出 Z (W^0的维度为hidden_size*hidden_size)。

Note: 多头的实现不是循环的计算每个头,而是通过 transposes and reshapes,用矩阵乘法来完成的。这样Multi-Head Attention时间复杂度(同如果只使用单头)也是

整个过程如图所示:

                                                        Multi-Head Attention

在例句中编码“it”一词时,不同的注意力“头”集中在哪里:当我们编码“it”一词时,一个注意力头集中在“animal”上,而另一个则集中在“tired”上,从某种意义上说,模型对“it”一词的表达在某种程度上是“animal”和“tired”的代表。

残差模块

        需要强调的最后一点是其采用了残差网络中的short-cut结构,目的当然是解决深度学习中的退化问题,得到的最终结果如图。

       Self-Attention中的short-cut连接

decode整体的动图

先通过encoder生成一个词。

再通过decoder生成后续的词。

其它

 神经网络的初始化是tf.truncated_normal_initializer(stddev=initializer_range)。

优化方式和优化方法Optimizer

代码实现

Transformer作者已经发布其在TensorFlow的tensor2tensor库中。

[Transformer Pytorch源码BERT Pytorch源码HuggingFace Transformers]

[pytorch-transformer code - jadore801120/attention-is-all-you-need-pytorch: A PyTorch implementation of the Transformer model in "Attention is All You Need".]

[苏剑林《Attention is All You Need》浅读(简介+代码)]

[code tensor2tensor/models/transformer.py]

from: http://blog.csdn.net/pipisorry/

ref: [BERT大火却不懂Transformer?读这一篇就够了 - 知乎][The Illustrated Transformer – Jay Alammar – Visualizing machine learning one concept at a time.]**

[The Annotated Transformer的中文注释版(1) - 知乎]

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/pipisorry/article/details/84946653

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签