Transformer详解

  • Transformer

    • 什么是transformer

    • 为什么需要用transformer

      • encoder

        • sub-encoder block

          • multi-head self-attention

          • FFN

        • input

      • decoder

        • input with look-ahead mask

        • sub-decoder block

      • output layer

      • summary

    • transformer的缺点

    • transformer的应用

    • ref

 

  • Transformer-XL

    • The motivation for Transformer-XL.

    • Transformer-XL: the proposed solution: Basic idea.

      • combine hidden states

      • how to compute self-attention

    • Absolute Positional Encoding & Memory:

    • summary

    • 应用和不足

    • ref


  • Self-Attention with Relative Position Representations

    • Relation-aware Self-Attention

    • Relative Position Representations

    • Implement

    • ref

  • Reformer

 

 

Transformer

什么是transformer

首先我们先说结论:Attention Is All You Need提出的transformer 其实就是 seq2seq + self attention。 代码实现, 非常清晰

seq2seq 任务指的是输入和输出都是序列的任务。例如说法语翻译成英文。

通常来说,Seq2Seq任务最常见的是使用encoder+decoder的模式,先将一个序列编码成一个上下文矩阵,在使用decoder来解码。当然,我们仅仅把context vector作为编码器到解码器的输入。

 

 

这样子往往得不到好的效果,因为我们的编码器的很多信息都无法完全编码在这个向量中,并且我们在解码的时候,对于输入的每个单词的权重是不一致的,所以在NMT任务上,还添加了attention的机制。

 

 

所以目前来说,我们可以直接先把transformer当成一个黑盒,就是transformer可以当成是一个序列转码的模型,只是它其中用了特殊的self-attention的机制。如下图所示:

 

 

为什么需要用transformer

在提到为什么需要用transformer的时候,我们需要了解,在没有transformer的时候,我们都是用什么来完成这系列的任务的呢?

其实在之前我们使用的是RNN(或者是其的单向或者双向变种LSTM/GRU等) 来作为编解码器。

RNN模块每次只能够吃进一个输入token和前一次的隐藏状态,然后得到输出。它的时序结构使得这个模型能够得到长距离的依赖关系,但是这也使得它不能够并行计算,模型效率十分低。

 

 

 

当然这边的的RNN可以通过CNN替换,从而达到并行的效果,可以看到下图,总共是两层的卷积层,第一层画出了两个filter,每个1D filter的size是2,到了第二层的卷积层的filter的size是3。

第一层的filter考虑的是两个字之间的关联,但是到了第二层,考虑了三个前一层输出的交互,从而考虑到了较长序列之间的关系。比如说这边序列是  , 第一层只考虑了  , ..  的交互,第二层考虑了  ,而  是前一层两两交互关系的结果,所以第二层考虑了  这个序列的结果了。

 

 

但是对于CNN每次一般我们的卷积核设的长度为3/5这种较小的值,对于序列长度较长的,比如512,就需要堆叠多层的卷积层,导致模型过于冗杂。

那么,我们有没有办法提出一个新的模型,能够并行,并且能够考虑到输入序列不同token的权重?聪明的科学家们提出了一种新的模型叫做transformer。

其实他就encoder+decoder模式,只是其中的编解码器采用了self-attention的机制。

 

 

当然transformer真的就比RNN好吗?有人提出,凡事用RNN做的模型,都可以直接用self-attention替代。这个我们会在transformer的缺点中讨论。# tranformer的内部结构

transformer其实是由encoder以及decoder不是单一模块,而是由小的多个sub-encoder block和sub-decoder block组成。

 

 

我们来看看transformer的具体结构图。由下图所示,它主要由左边的encoder+input以及右边的decoder+input+output组成。我们将会一一介绍。

 

 

encoder

这边的encoder由input以及多个sub-encoder blocks组成。我们将会先讲sub-encoder,再讲输入,因为输入的设计是为了弥补self-attention的缺陷的。

sub-encoder block

首先每个sub-encoder都由两个主要的部分组成(略过部分细节,之后会写),分别是self-attention layer以及ffn layer。

具体的实现机制就是:我们的输入每个词经过embedding 之后,然后经过self-attention ,根据自己的路径,经过转换得到新的输出vector,最后再经过ffn layer,得到新的输出,作为下一层sub-encoder的输入。

 

 

multi-head self-attention

首先我们先了解一下self-attention的作用,其实self attention大家并不陌生,比如我们有一句话,the animal didnot cross the street, because it was too tired. 这里面的it,指代的是the animal。我们在翻译it的时候会将更多的注意力放在the animal身上,self-attention起的作用跟这个类似,就是关注句子中的每个字,和其它字的关联关系。参考实现

 

 

我们来看看这些词是怎么经过multi-head attention,得到转换的。

首先我们每个字的输入vector  会经过变换得到三个vector,分别是query  , key  以及value  , 这些向量是通过输入  分别和query矩阵  ,key矩阵  ,value矩阵  相乘得来的。query矩阵  ,key矩阵  ,value矩阵  都是训练时学习而来的。

 

 

将 x1 和 WQ weight matrix 做矩阵乘法得到 q1, 即这个字对应的query向量. 类似地,我们最终得到这个字对应query向量,value向量,key向量。- query向量:query顾名思义,是负责寻找这个字的于其他字的相关度(通过其它字的key) - key向量:key向量就是用来于query向量作匹配,得到相关度评分的 - value向量:Value vectors 是实际上的字的表示, 一旦我们得到了字的相关度评分,这些表示是用来加权求和的

 

 

得到每个字的  之后,我们要得到每个字和句子中其他字的相关关系,我们只需要把这个字的query去和其他字的key作匹配,然后得到分数,最后在通过其它字的value的加权求和(权重就是哪个分数)得到这个字的最终输出。

 

Transformer详解_第1张图片

 

我们来具体看看这个分数是怎么计算得到的。我们之前看到的都是单个字作self-attention,但是在GPU中,其实整个过程是并行的,一个序列  是同时得到每个  对应的Q,K,V的,这是通过矩阵乘法。

 

 

然后每个字与其他字对应的score的算法采用的是Scaled Dot-product Attention

具体就是以下公式

  • 其中  。

  • 其中,scale因子是输入的vector size  开根号。

总结来说:

 

等等,那么什么是multi-head呢?首先我们先了解一下什么是multi-head,其实很简单,就是我们刚才这个sub-encoder里面,我们的self-attention,只做了一次, 如果我们引入多个不同的  , 然后重复刚才的步骤,我们就可以得到multi-head了。

 

在得到多个  向量之后,我们把这些向量concat起来,然后再经过线性变换,得到最终的输出。

 

那么我们为什么需要multi-head呢?这是因为,他可以提高模型的能力 - 这使得模型能够关注不同的位置,比如句子经济。。。,教育。。。,这使得这座城市发展起来了,句子中的在不同的head中,可以着重关注不同的地方例如经济教育。亦或者如下面的栗子。

 

  • 就像是CNN采用不同的不同的kernel的效果,不同的kernel能过获取的信息不同,类似的,不同的head,能够扩展模型的不同表示空间(different representation subspaces),因为我们有不同的QKV,这些都是随机初始化,然后通过训练得到最总结果,并且结果往往不同。关于different representation subspaces,举一个不一定妥帖的例子:当你浏览网页的时候,你可能在颜色方面更加关注深色的文字,而在字体方面会去注意大的、粗体的文字。这里的颜色和字体就是两个不同的表示子空间。同时关注颜色和字体,可以有效定位到网页中强调的内容。使用多头注意力,也就是综合利用各方面的信息/特征。

  • 我觉得也可以把多头注意力看作是一种ensemble,模型内部的集成。

FFN

在self-attention层之后模型会经过FFN层。\begin{equation} FFN(x) = max(0, xW_1 + b_1 )W_2 + b_2 \end{equation} 这边的实现就是两层的Dense layer,第一层的激活函数是RELU。

 

两个sub-layer的连接并不是直接相连,而是先通过ADD&Normalize层,所谓的ADD&Normalize层,由以下两个组成

- ADD:将输入+self-attention的输出 - Normalize:在经过layer-normalization以及dropout操作。

layer normalization:其实很简单就是每一条样本都经过(x-mean) / std, 其mean和std 都是按照单条样本进行计算的。

input

对于encoder的输入,由于self-attention的机制讲没有考虑输入序列的顺序,但是一个句子的输入顺序其实很重要,例如你喜欢苹果不,你不喜欢苹果,两个句子的含义不同,所以我们需要为输入embedding添加position encoding。

 

 

这边的position encoding,主要可以分为通过序列的关系可以分为 - 绝对位置:例如每个sequence  , 位置都是从0,1..n开始 - 相对位置:位置的表示是由字与字之间的差表示的。相对位置表达Relative Position Representations (RPR)是Shaw et al., 2018,这个论文指出,同一个sequence中使用相对位置更好。

它根据encoding的方式也可以分为, - functional encoding: 这个是指的是通过特定函数的方式,将输入的位置idx变换为embedding。- parametric encoding:指的是通过embedding loopup的方式,让模型自己学习位置的embedding 这两种方式的效果都差不多,但是functional的可以减少模型的参数。

BERT使用的是 parametric absolute positional encoding (PAPE) 而transformer使用的是functional absolute positional encoding (FAPE)。

这边的函数使用的是正弦位置编码:

  •  指的是模型输出的embedding size

  • pos 代表是字在序列中的位置

  •  代表的是position embedding 之后的第  维,即  这个公式比较具有迷惑性,特别是论文中的写法,结合例子就比较好理解了,如pos=3,d(model)=128,那么3对应的位置向量如下: 

 

 

 

这个编码函数的可视化结果:

 

decoder

编码器完成之后我们需要解码器进行工作,最后一层的输出会被转化为一组 attention vectors K and V. 作为encoder-decoder attention层的K,V矩阵使用,这些能够帮助decoder关注输入的合适位置。

 

每一个timestamp的输出都会被喂给decoder,我们将这个输出做embedding 输出在添加position encoding。decoder的解码工作的停止条件就是知道特殊字符\ 得到了。

input with look-ahead mask

decoder的输入和encoder的输入不太一样,引文decoder的self-attention layer只能够关注输出序列当前位置以及之前的字,不能够关注之后的字。所以这边需要将这之后的字都添加上mask,即q*k之后加上负无穷(-inf),使得其再经过softmax之后的权重变为0。

The look-ahead mask is used to mask the future tokens in a sequence. In other words, the mask indicates which entries should not be used.

look-ahead mask 是用来mask序列的future tokens。具体的做法如下:

def create_look_ahead_mask(size):
  mask = 1 - tf.linalg.band_part(tf.ones((size, size)), -1, 0)
  return mask  # (seq_len, seq_len)

x = tf.random.uniform((1, 3))
temp = create_look_ahead_mask(x.shape[1])
>>>array([[0., 1., 1.],
>>       [0., 0., 1.],
>>       [0., 0., 0.]], dtype=float32)>

刚看到这边的时候,我有个问题,就是decoder的每次timestamp的输入不都是之前的前一次的输出吗,如何并行?这不是跟RNN一样?但是其实在训练的时候,我们是把所有的target 的序列直接作为decoder的输入的!然后通过look-ahead mask来模拟不同timestamp。

sample_decoder = Decoder(num_layers=2, d_model=512, num_heads=8,
                         dff=2048, target_vocab_size=8000,
                         maximum_position_encoding=5000)
target_input = tf.random.uniform((64, 26), dtype=tf.int64, minval=0, maxval=200)

output, attn = sample_decoder(target_input,
                              enc_output=sample_encoder_output,
                              training=False,
                              look_ahead_mask=None,
                              padding_mask=None)

在预测的时候,才是真正将decoder的输出作为下一次的输入。但这时候模型已经是一个黑盒了。

def evaluate(inp_sentence):
  start_token = [tokenizer_pt.vocab_size]

  end_token = [tokenizer_pt.vocab_size + 1]

  # inp sentence is portuguese, hence adding the start and end token
  inp_sentence = start_token + tokenizer_pt.encode(inp_sentence) + end_token
  encoder_input = tf.expand_dims(inp_sentence, 0)

  # as the target is english, the first word to the transformer should be the
  # english start token.
  decoder_input = [tokenizer_en.vocab_size] # 
  output = tf.expand_dims(decoder_input, 0)

  for i in range(MAX_LENGTH):
    print(output)
    enc_padding_mask, combined_mask, dec_padding_mask = create_masks(
        encoder_input, output)
    predictions, attention_weights = transformer(encoder_input,
                                                 output,
                                                 False,
                                                 enc_padding_mask,
                                                 combined_mask,
                                                 dec_padding_mask)

    # select the last word from the seq_len dimension
    predictions = predictions[: ,-1:, :]  # (batch_size, 1, vocab_size)

    predicted_id = tf.cast(tf.argmax(predictions, axis=-1), tf.int32)

    # return the result if the predicted_id is equal to the end token
    if predicted_id == tokenizer_en.vocab_size+1: # 
      return tf.squeeze(output, axis=0), attention_weights

    # concatentate the predicted_id to the output which is given to the decoder
    # as its input.
    output = tf.concat([output, predicted_id], axis=-1)

  return tf.squeeze(output, axis=0), attention_weights
translate("este é um problema que temos que resolver.")
print ("Real translation: this is a problem we have to solve .")
>> tf.Tensor([[8087]], shape=(1, 1), dtype=int32)
>> tf.Tensor([[8087   16]], shape=(1, 2), dtype=int32)
>> tf.Tensor([[8087   16   13]], shape=(1, 3), dtype=int32)
>> tf.Tensor([[8087   16   13    7]], shape=(1, 4), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328]], shape=(1, 5), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10]], shape=(1, 6), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10   14]], shape=(1, 7), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10   14   24]], shape=(1, 8), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10   14   24    5]], shape=(1, 9), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10   14   24    5  966]], shape=(1, 10), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10   14   24    5  966   19]], shape=(1, 11), dtype=int32)
>> tf.Tensor([[8087   16   13    7  328   10   14   24    5  966   19    2]], shape=(1, 12), dtype=int32)
Input: este é um problema que temos que resolver.
Predicted translation: this is a problem that we have to solve it .
Real translation: this is a problem we have to solve .

sub-decoder block

sub-decoder block 跟encoder几乎一样,只是它比普通的encoder多了一个Encoder-Decoder Attention,The “Encoder-Decoder Attention” layer和multiheaded self-attention的工作机制一样,除了它使用的是 Keys 和 Values matrix 是encoder的输出, 这就意味着,我们decoder的query考虑到了encoder的所有的字了。

 

 

output layer

decoder的output是一个vector,这时候再经过一个dense层得到vocabulary size的logits,再经过softmax在取argmax得到输出的字。

 

summary

 

Transformer详解_第2张图片

 

class Transformer(tf.keras.Model):
  def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size,
               target_vocab_size, pe_input, pe_target, rate=0.1):
    super(Transformer, self).__init__()

    self.encoder = Encoder(num_layers, d_model, num_heads, dff,
                           input_vocab_size, pe_input, rate)

    self.decoder = Decoder(num_layers, d_model, num_heads, dff,
                           target_vocab_size, pe_target, rate)

    self.final_layer = tf.keras.layers.Dense(target_vocab_size)

  def call(self, inp, tar, training, enc_padding_mask,
           look_ahead_mask, dec_padding_mask):

    enc_output = self.encoder(inp, training, enc_padding_mask)  # (batch_size, inp_seq_len, d_model)

    # dec_output.shape == (batch_size, tar_seq_len, d_model)
    dec_output, attention_weights = self.decoder(
        tar, enc_output, training, look_ahead_mask, dec_padding_mask)

    final_output = self.final_layer(dec_output)  # (batch_size, tar_seq_len, target_vocab_size)

    return final_output, attention_weights

transformer的缺点

  • tranformer 的空间以及时间复杂度非常大,sequence length  , 达到  ,这是因为每一层的self attention 都要储  的score用于之后的更新,所以L的长度不能很大,否则会遇到OOM的问题。在这种情况下,如果一个句子特别长, 那么他就不得不被分为两个sequence作为输入,但是这个时候前后句子之间的关系就没了,但是RNN可以不管多长的输入都能handle。

  • 运行时间太慢,模型太大

  • position encoding 使用absolute encoding,而Self-Attention with Relative Position Representations指出了相对位置更好

transformer的应用

翻译等, summary

ref

李宏毅transformer

Attention Is All You Need

the-illustrated-transformer

The Evolved Transformer – Enhancing Transformer with Neural Architecture Search

Transformer-XL – Combining Transformers and RNNs Into a State-of-the-art Language Model7

code


Transformer-XL

The motivation for Transformer-XL.

首先,为什么会提出transformerXL呢,它的提出主要是为了解决transformer的问题。我们首先先分析一下RNN以及Transformer的优缺点。

  • RNN

    • 优点:

      • 支持可变长

      • 支持记忆

      • 有序列顺序关系

    • 缺点:

      • gradient vanish

      • 耗时,无法并行

  • Transformer

    • 优点:

      • 并行

      • 考虑到sequence的long term dependency信息(相对于RNN)

      • 可解释性

    • 缺点:

      • 句子与句子之间的关系

      • batch size也不能很大

      • 空间占用大(因为我每个encoder的score matrix(sequenceLen*sequecenLen是 的空间复杂度(BOOOOM!) 如下图

 

  • 解决的方案,将文章documnet切成segments,喂给transformer

但是segment之间没有信息传递,This problem is called context fragmentation.!

The daughter had a nice umbrella that her mother gave her.  daughter and  her are in different segment

前后句就不能够了解这个雨伞是他妈妈给的

那么如果解决这个问题呢?我们其实只需要使用RNN的 hidden state来解决信息的传递,我们在不同的segment之间传入传递memory信息。

 

Transformer-XL: the proposed solution: Basic idea.

所以transformer:(1+2: positional embedding, 3: stacks of encoders)

 

 

升级变成下图(注意是embedding/hidden output的concat,不是score的concat)

 

 

可以简单的理解 transformerXL = transformer + RNN => segment-wise的RNN Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context

 

对于所有的encoder i 除了最后一个encoder
  Set h_{-1,i } 为全0矩阵,矩阵形状和之后的segment的output矩阵形状一致
当我们计算 segment 0时:
  对于所有的encoder i 除了最后一个encoder:
    Combine the saved hidden states: h_{-1,i-1} and h_{0,i-1}.
  对于所有的encoder i 除了最后一个encoder:
    Make a copy of its output h_{0,i }(hidden state).
当我们计算segment 1时:
  对于所有的encoder i 除了最后一个encoder:
    Combine the saved hidden states: h_{0,i-1} and h_{1,i-1}.
  对于所有的encoder i 除了最后一个encoder:
    Make a copy of its output h_{1,i }(hidden state).
…
当我们计算 segment t:
  对于所有的encoder i 除了最后一个encoder:
    Combine the saved hidden states: h_{t-1,i-1} and h_{t,i-1}.
  对于所有的encoder i 除了最后一个encoder:
    Make a copy of its output h_{t,i }(hidden state).
* This shape will be (batch_size, segment_len, emb_dim).

combine hidden states

 

我们来看看如何Combine the saved hidden states: h_{t-1,i-1} and h_{t,i-1}.,其实很简单,就是直接直接在 segment 这个维度上面concat起来。

 

原本的输出shape(batch_size, segment_len, emb_dim), 现在的combinate之后,输出变成了(batch_size, 2*segment_len, emb_dim)

值得注意的是,在训练的时候,我们是不用反向传播更新我们的memery的,我们的memory是之前的sequence的结果,我们可以在pytorch中设置.requires_grad=False

how to compute self-attention

在做self-attention的时候,输入的  作为from_tensor 和to_tensor自己attend to 自己,  用来产生Q,K,V矩阵,但是在transformer-XL中,我们的query Q用的仍然是我们的输  产生,但是K,V,都是用的是  , 其中 

 

 

 

softmax 出来的结果:

 

对于decoder来说我们需要加上一个look-ahead mask,就和trasnformer

 

 

我们每次都只concat前一次的  ,这是因为我们认为我们前一次的输出已经包括了之前所有的信息了。

Absolute Positional Encoding & Memory:

 

 

如果我们继续使用之前的absolute positing encoding的话,对于所有的sequence的序列,只要这个字在序列中的位置一样的话,它的position encoding也会一样,这样的话,对于我们concat之后的输出,我们无法区别每个字的位置。

如下图:Thethat的position encoding完全一样,模型无法区分两者位置区别。

 

 

所以Transformer-XL 首先分析了position encoding在计算中的作用,然后根据这个结果将交互项转化为relative position encoding。

  • 分析了每个position encoding在计算中的作用

  •  : embeddimng+position encoding

  •  : Q

  •  : 

The notation  refers to the entire row  and  to the entire column  . 经过计算,这个式子可以分为4项。

  • a) 这一项中没有包含  位置信息,代表的是在第  行的字应该对第  列的字提供多大的注意力。这是不管他们两个字的位置信息的。

  • b) 这一项捕获的是模型的global attention,指的是一个字在position 应该要对 position 付出多大的注意力。例如两个字的位置越远,期望它们之间的注意力越小。

  • c) 这一项捕获的是在row i的字对其他位置的关注信息,例如在position i是一个字"狗", 应该要对j=i-1 这个位置特别注意,否则可能出现j=i-1是“热”, 出现是“热狗”的情况。

  • d) 这个是c) 的逆向表示,指的是j的字要pay attention to 位置i的字。

  • 根据这个观测,转化relative position 通过了解了每一项的意义,我们了解了两个字的相对位置对这个score的作用。我们将 b), c) and d) 替换为如下式子。

 

 

我们可以看到主要的变化

  • 我们将使用的是相对的position encoding i.e. 取消 P_{•, j}  而采用  相对位置。

  • 每次使用  我们都将  替换为  (两者的形状相同)。这是为了区别  (仍使用) 和  ,使得两者可以各自捕获有意义的位置信息而不会相互干预,因为  和  相匹配,而  和  像对于。

  •  这一项被替代为 u  和  ,这两个向量的维度为 (1, d_k)。因为我们使用的是相对位置编码,所以我们并不需要提供绝对位置  ,所以我们可以直接把整项替换掉。这边使用两个向量的原因是因为一项是更换了相对位置(b),一项没有(d),所以这样能够focus on the general position and the position given the word we attend to as its the case of u and v respectively.(这边没有非常理解)

所以  的公式被替换为: 

summary

  • Memory between segments

  • Change from Absolute to Relative Positional Encoding.

应用和不足

最主要的应用是他用在XLNET上 不足的话,memory的公式的设计不好,直接concat。以及relative position encoding的设计也不是很合理。

ref

Dissecting Transformer-XL

Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context

 

Self-Attention with Relative Position Representations

Self-Attention with Relative Position Representations 论文中还发现,+relative position encoding 在transformer的translation的task上得到了提升,但是结合了absolute以及relative的话,效果没提升。

论文很短,很容易理解。

首先我们先了解在self-attention中,我们  的计算: 

Relation-aware Self-Attention

文章中引入了两个位置相关的向量,量:  ,之所以采用  维向量的表示形式,主要是为了套用原来self-attention的计算公式, 因为  的维度是这个。  是在所有的attention layer中共享的。

在引入了这两个相对位置信息向量之后上式(1)将改编为:

Relative Position Representations

Relative Position Representations的目标是给出  的计算方式。作者假设如果序列中两个元素的距离超过k,则这两元素之间的位置信息就没有意义了。同时,  应该只跟相对位置有关,而与  没有关系。作者直接将  定义为了可训练的向量,本质上是训练  和  :

其中clip函数的作用就是截断  的长度,使得其落在  之间

 

A矩阵的示意图,k代表了考虑的距离,箭头表示的一对相对位置表示。

注意:这边的主要给出了  的表示方式,这是论文中最难的部分,但是理解了就不难了,其实就是一个一个可训练的矩阵

Implement

tensor reshaping can be used to compute n parallel multiplications of bh×d zand d z×n matrices. Each matrix multiplication computes contributions to eij for all heads and batches, corresponding to a particular sequence position. Further reshaping allows adding the two terms. The same approach can be used to efficiently compute z_i

ref

Self-Attention with Relative Position Representations Self-Attention with Relative Position Representations 解读

Reformer

REFORMER : THE EFFICIENT TRANSFORMER是google 2020 的一篇重量级的文章,文章中主要做了如下的改进,是的模型的复杂度从  变为了  。文章思路还是很清晰的,但是不好理解,需要多读几遍,先占坑。主要解决的痛点是

  • - transformer模型的空间复杂度高,所以sequence length必须不能很长,batch size也不能很大。

  • - 时间复杂度高,训练时间长

采用的方式

  • - Reversible layers

  • - Locality Sensitive Hashing Attention

  • - Chunking FFN layers

你可能感兴趣的:(机器学习算法)