【深度学习】李宏毅:图解 Transformer

Transformer

Transformer 是 2017 年引入的深度学习模型,主要用于自然语言处理领域。与循环神经网络一样,Transformers 旨在处理顺序数据(例如自然语言),以执行翻译和文本摘要等任务。但是,与 RNN 不同,Transformers 不需要按顺序处理顺序数据。

Attention is all you need: 意即不需要  和 ,只需要

Why do we need the Transformer?

  • RNN
    • 是最经典的处理 Sequence 的模型,单向 RNN 或双向 RNN 等等。
    • RNN 存在的问题:难以并行化处理

Hard to parallel

于是,就有人提出用 CNN 取代 RNN

Using CNN to replace RNN

  • CNN 替代 RNN

    • CNN filters:每一个三角形代表一个 filter 输入为 seq 的一小段,输出一个数值(做内积得到),不同的 filter 对应 seq 中不同的部分。

    Using CNN to replace RNN (CNN can parallel)

    • 每一个 CNN 只能考虑有限的内容,RNN 能考虑一整个句子
    • 考虑很长的句子:叠很多层 CNN,上层的 filter 就可以考虑较多资讯,因为上层的filter会把下层的filter的输出当作输入
    • 问题:必须叠很多层才有办法做到考虑较长的句子,因此出现了 self-attention 机制

    You can try to replace any thing that has been done by RNN with self-attention.

self-attention layer

例如,输入 x 1 , x 2 , x 3 , x 4 x_1,x_2,x_3,x_4 x1,x2,x3,x4 通过 embedding 得到 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4 a1,a2,a3,a4,每一个 input 都分别乘以三个不同的 transformation(矩阵)得到三个不同的 vector q , k , v q,k,v q,k,v

  • q q q: query (to match others)

q i = W q a i q^i = W^q a^i qi=Wqai

  • k k k: key (to be matched)

k i = W k a i k^i = W^k a^i ki=Wkai

  • v v v: information to be extracted

v i = W v a i v^i = W^v a^i vi=Wvai

Self attention layer

拿每个 query q q q 去对每个 key k k k 做 attention,文中使用 Scaled Dot-Product Attention:
α 1 , i = q 1 ⋅ k i / d \alpha_{1,i} = q^1 \cdot k^i / \sqrt{d} α1,i=q1ki/d
其中, ⋅ \cdot 表示 dot product, d d d q q q 的维度,能够抵消因维度引起的不平衡。

attention

然后,再进行 softmax 进行激活
α ^ 1 , i = exp ⁡ ( α 1 , i ) ∑ j exp ⁡ ( α 1 , i ) \hat{\alpha}_{1,i} = \frac{\exp \left( \alpha_{1,i} \right)}{\sum\limits_j \exp\left( \alpha_{1,i} \right)} α^1,i=jexp(α1,i)exp(α1,i)
softmax

拿每个 query q q q 去对每个 key k 做 attention
b 1 = ∑ i α ^ 1 , i v i b^1 = \sum\limits_i \hat{\alpha}_{1,i} v^i b1=iα^1,ivi
乘和

这样, b 1 , b 2 , b 3 , b 4 b^1,b^2,b^3,b^4 b1,b2,b3,b4 可以并行计算得到。

接下来,使用矩阵运算来说明 self-attention layer 的过程:

  • Step 1:

Step 1

  • Step 2:

Step_2

  • Step 3:
    Step_3

  • Step 4:

Step 4

于是,可得
Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=softmax(dk QKT)V
如下图所示:

Transformer 矩阵计算

反正就是一堆矩阵乘法,可以用 GPU 可以加速

Multi-head Self-attention

Multi-head Self-attention 允许模型共同注意来自不同位置的不同表示子空间的信息。不同的 head 可以各司其职,学习到不同意义的特征(如 local 的或者 global 的)。
MultiHead ( Q , K , V ) = Concat ( head 1 , ⋯   , head h ) W O \text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1,\cdots,\text{head}_h) W^O MultiHead(Q,K,V)=Concat(head1,,headh)WO
其中
head i = Attention ( Q W i Q , K W i K , V W i V ) \text{head}_i = \text{Attention}(QW_i^Q,KW_i^K, VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)
下图是 2 head 的注意力图

2 head self-attention example

得到 b i , 1 , b i , 2 b^{i,1},b^{i,2} bi,1,bi,2 可以通过 concatenate 进行拼接,还可以引入 W W W 进行维度的变化

进行维度变换

Positional Encoding

  • 原始的 self-attention没有考虑位置信息,所以可以引入一个的位置向量 e i e_i ei,不是学出来的而是人设置的。
  • 其他方法:使用 one-hot encoding 表示的 p i p_i pi x i x_i xi 表示其位置

引入一个未知向量

具体地,可以将 x x x p p p 进行 concatenate 或者上图直接在 a i a^i ai 中加入 e i e^i ei

pos_2

keras 官方给出的 embedding layer 实现如下

class TokenAndPositionEmbedding(layers.Layer):
    def __init__(self, maxlen, vocab_size, embed_dim):
        super(TokenAndPositionEmbedding, self).__init__()
        self.token_emb = layers.Embedding(input_dim=vocab_size, output_dim=embed_dim)
        self.pos_emb = layers.Embedding(input_dim=maxlen, output_dim=embed_dim)

    def call(self, x):
        maxlen = tf.shape(x)[-1]
        positions = tf.range(start=0, limit=maxlen, delta=1)
        positions = self.pos_emb(positions)
        x = self.token_emb(x)
        return x + positions

Seq2seq Architecture

原始 seq2seq2 model 由两个 RNN 分别组成了 Encoder、Decoder,可以应用于机器翻译。

Encoder-decoder-orignal

上图中原本 Encoder 里面是双向 RNN,Decoder 里面是一个单向 RNN,下图把两个都用 Self-attention layer 取代,可以到达一样的目的而且可以平行运算。

Encoder-decoder

一个动画形象地刻画这一过程

Transformer: A Novel Neural Network Architecture for Language Understanding")

Transformer

下图是 transformer 的架构图:

Transformer Architecture

  • Encoder

    • Input 通过 Input Embedding,考虑位置资讯,加上人为设置的 Positional Encoding,进入会重复 $N $次的 block

      • Multi-head:进到 Encoder 里面,他是 Multi-head Attention的,也就是 q , k , v q,k,v q,k,v 有多个,在里面做 q k v qkv qkv 个别乘以 a a a 的运算,算出 α \alpha α 最后得到 b b b

      • Add & Norm: 把 Multi-head attentioninput a a aoutput b b b 加起来得到 b ′ b' b,再做 Layer Normalization
      • 计算完后丢到前向传播,再经过一个 Add & Norm
  • Decoder

    • input 为前一个 time step 的 output,通过 output embedding,考虑位置资讯,加上人为设置的 positional encoding,进入会重复 n n n 次的 block
      • Masked Multi-head Attention:做Attention,Masked 表示只会 attend 到已经产生出来的 sequence,再经过 Add & Norm Layer
      • 再经过 Multi-head Attention Layer,attend 到之前 Encoder 的输出,然后再进到 Add & Norm Layer
      • 计算完丢到 Feed Forward 前向传播,再做 LinearSoftmax,产生最终输出

Transformer block 实现如下:

class TransformerBlock(layers.Layer):
    def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):
        super(TransformerBlock, self).__init__()
        self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)
        self.ffn = keras.Sequential(
            [layers.Dense(ff_dim, activation="relu"), layers.Dense(embed_dim),]
        )
        self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)
        self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)
        self.dropout1 = layers.Dropout(rate)
        self.dropout2 = layers.Dropout(rate)

    def call(self, inputs, training):
        attn_output = self.att(inputs, inputs)
        attn_output = self.dropout1(attn_output, training=training)
        out1 = self.layernorm1(inputs + attn_output)
        ffn_output = self.ffn(out1)
        ffn_output = self.dropout2(ffn_output, training=training)
        return self.layernorm2(out1 + ffn_output)

下载和准备数据集:

vocab_size = 20000  # Only consider the top 20k words
maxlen = 200  # Only consider the first 200 words of each movie review
(x_train, y_train), (x_val, y_val) = keras.datasets.imdb.load_data(num_words=vocab_size)
print(len(x_train), "Training sequences")
print(len(x_val), "Validation sequences")
x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen)
x_val = keras.preprocessing.sequence.pad_sequences(x_val, maxlen=maxlen)

使用 transformer 创建分类器模型

embed_dim = 32  # Embedding size for each token
num_heads = 2  # Number of attention heads
ff_dim = 32  # Hidden layer size in feed forward network inside transformer

inputs = layers.Input(shape=(maxlen,))
embedding_layer = TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim)
x = embedding_layer(inputs)
transformer_block = TransformerBlock(embed_dim, num_heads, ff_dim)
x = transformer_block(x)
x = layers.GlobalAveragePooling1D()(x)
x = layers.Dropout(0.1)(x)
x = layers.Dense(20, activation="relu")(x)
x = layers.Dropout(0.1)(x)
outputs = layers.Dense(2, activation="softmax")(x)

model = keras.Model(inputs=inputs, outputs=outputs)

训练和评估

model.compile("adam", "sparse_categorical_crossentropy", metrics=["accuracy"])
history = model.fit(
    x_train, y_train, batch_size=32, epochs=2, validation_data=(x_val, y_val)
)

打印信息如下:

Epoch 1/2
782/782 [==============================] - 15s 18ms/step - loss: 0.5112 - accuracy: 0.7070 - val_loss: 0.3598 - val_accuracy: 0.8444
Epoch 2/2
782/782 [==============================] - 13s 17ms/step - loss: 0.1942 - accuracy: 0.9297 - val_loss: 0.2977 - val_accuracy: 0.8745

Attention Visualization

  • single head

文字俩俩之间的关系,线条越粗代表关联越深

  • multi-head

用不同组的  配对出来的结果有所不同,代表不同组的  拥有不同资讯(下面 local or 上面 global)

Example Application

  • Summarizer By Google

input 为一堆文档,output 为一篇文章(summarize)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fEMpvaW3-1612535321252)(https://arxiv.org/abs/1801.10198 “Generating Wikipedia by Summarizing Long Sequences”)]](https://cdn.jsdelivr.net/gh/ZhouKanglei/jidianxia/2021-2-5/1612530043763-example.png)

  • Universal Transformer

横向(时间上)是Transformer,纵向是RNN

(https://ai.googleblog.com/2018/08/moving-beyond-translation-with.html "Universal Transformer")

  • Self-Attention GAN

也可以用在影像生成上

Self-Attention GAN

猜你喜欢

转载自blog.csdn.net/qq_38904659/article/details/113705027