Transformerの構造を理解したい


こんにちは、すきにーです。

Transformerのこの図がずっと理解できなかったのですが、
最近理解することができました。

この記事で自分なりに解説していきたいと思います。

![transfrormer](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/57a03a7b-beb2-64c0-e153-bae7190a6d4b.png)

コードはかなり簡略化して書いてます。
# はじめに
## この記事で説明していること
   TensorFlow公式ドキュメント, Transformerモデル
https://www.tensorflow.org/tutorials/text/transformer

[エンコーダーとデコーダー](https://www.tensorflow.org/tutorials/text/transformer?hl=ja#%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC%E3%81%A8%E3%83%87%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC)から[Transformerの作成](https://www.tensorflow.org/tutorials/text/transformer?hl=ja#transformer%E3%81%AE%E4%BD%9C%E6%88%90)のところまでを説明しています。
　
## 参考にした記事
[作って理解する Transformer / Attention](https://qiita.com/halhorn/items/c91497522be27bde17ce)
[深層学習界の大前提Transformerの論文解説！](https://qiita.com/omiita/items/07e69aef6c156d23c538)
[【Pytorch】Transformerを実装する](https://qiita.com/gensal/items/e1c4a34dbfd0d7449099)
[図で理解するTransformer](https://qiita.com/birdwatcher/items/b3e4428f63f708db37b7)


# Transformerの構造

## 全体図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/24b194c6-8574-4914-e941-a69afe97734d.png)

入力 → Encoder → Decoder → 出力という構造になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/3602f8e1-c9f4-74fa-7c3a-d07e55a61be8.png)
出典：https://kikaben.com/transformers-encoder-decoder/

エンコーダーとデコーダーの中身が複雑になっているので、分かり辛くなっているのだと思いました。

簡単に書くとこんな感じ
```py
class Transformer(tf.keras.Model):
  def __init__():
    self.encoder = Encoder()
    self.decoder = Decoder()
    self.final_layer = tf.keras.layers.Dense()

  def call(self, encoder_input, decoder_input):
    #エンコーダーの出力
    encoder_output = self.encoder(encoder_input)  

    #エンコーダーの出力をデコーダーにいれて、デコーダから出力
    decoder_output, attention_weights = self.decoder(encoder_output, decoder_input) 

    #最終的な出力
    output = self.final_layer(decoder_output)  

    return output, attention_weights
```
## Encoder
エンコーダーはこの図の左側です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/d171c79b-ac40-fade-0952-65950edcb402.png)
そして、青枠の部分をエンコーダーレイヤー（EncoderLayer）と言います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/75781a55-4c4f-2c82-a7b3-9b7150c9eb65.png)

エンコーダーレイヤーを1つの層として考えると、エンコーダはこのような構造になっています。
①入力の埋め込み
↓
②位置エンコーディング
↓
③エンコーダーレイヤー × N
↓
④出力

pythonで書くと次のようになります。
```py
class Encoder(tf.keras.layers.Layer):
  def __init__():
    super(Encoder, self).__init__()
    self.d_model = d_model

    #入力の埋め込み
    self.embedding = tf.keras.layers.Embedding()

    #位置エンコーディング
    self.pos_encoding = positional_encoding()

    #エンコーダーレイヤー
    self.enc_layers = EncoderLayer() 

  def call(self, x, training, mask):

    seq_len = tf.shape(x)[1]

    # 入力埋め込み
    x = self.embedding(x) 

    #埋め込みと位置エンコーディングを合算する
    x += self.pos_encoding[:, :seq_len, :]

    #エンコーダーレイヤーの処理をN回繰り返す
    for i in range(N):
      x = self.enc_layers[i](x, training, mask)
    
    #出力
    return x  
```

## EcoderLayer
下図がエンコーダーレイヤーです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/63d8ecab-ef53-d7e3-b781-c2dea7ea99b0.png)

主にやっていることは2つしかありません。
①マルチヘッドアテンション
②ポイントワイズ・フィードフォワード・ネットワーク

Add＆Norm の部分は勾配消失の回避や学習の安定化のためにやっている処理なので、今回は飛ばします。
```py
class EncoderLayer(tf.keras.layers.Layer):
  def __init__():
    super(EncoderLayer, self).__init__()
    self.mha = MultiHeadAttention()
    self.ffn = point_wise_feed_forward_network()

  def call(input):

    # ①マルチヘッドアテンション
    attntion_output, _ = self.mha(input) 

    # ②ポイントワイズ・フィードフォワード・ネットワーク
    output = self.ffn(attntion_output)

    return output
```



## Decoder
デコーダーは、エンコーダーとほとんど同じです。
処理が一つ増えてるだけ。

デコーダーはこの図の右側になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/8cfc045d-8bb8-d064-05a8-49ff7ea11a11.png)

そして、青枠の部分をデコーダーレイヤー（DecoderLayer）と言います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/4be075b4-c8ef-6214-9e17-93da5b472eae.png)


デコーダーレイヤーを1つの層として考えると、デコーダはこのような構造になっています。
①入力の埋め込み
↓
②位置デコーディング
↓
③デコーダーレイヤー × N
↓
④出力

pythonで書くと次のようになります。
```py
class Decoder(tf.keras.layers.Layer):
  def __init__():
    super(Decoder, self).__init__()
    self.d_model = d_model

    #入力の埋め込み
    self.embedding = tf.keras.layers.Embedding()

    #位置デコーディング
    self.pos_Decoding = positional_Decoding()

    #デコーダーレイヤー
    self.dec_layers = DecoderLayer() 

  def call(self, x, training, mask):

    seq_len = tf.shape(x)[1]

    # 入力埋め込み
    x = self.embedding(x) 

    #埋め込みと位置デコーディングを合算する
    x += self.pos_Decoding[:, :seq_len, :]

    #デコーダーレイヤーの処理をN回繰り返す
    for i in range(N):
      x, weights = self.dec_layers[i](x, training, mask)
    
    #出力
    return x, weights
```

## DecoderLayer
下図がデコーダーレイヤーです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/063fe75b-ef48-89b0-3a7e-bd2715891a5a.png)

エンコーダーレイヤーと違うところは、2つしかありません。

1. エンコーダーの出力を受け取って処理する層が追加されている
2. マルチヘッドアテンションが未来の情報にアクセスできないように制限されている。（Masked Multi-Head Attentionになっている）


デコーダーレイヤーの処理は3つです。
①Masked Multi-Head Attention
②エンコーダからの出力をマルチヘッドアテンションで処理
③ポイントワイズ・フィードフォワード・ネットワーク

Add＆Norm の部分は勾配消失の回避や学習の安定化のためにやっている処理なので、今回は飛ばします。
```py
class DecoderLayer(tf.keras.layers.Layer):
  def __init__():
    super(DecoderLayer, self).__init__()

    self.mha1 = MultiHeadAttention()
    self.mha2 = MultiHeadAttention()

    self.ffn = point_wise_feed_forward_network()

  def call(input, encoder_output, mask):

    # ①Masked Multi-Head Attention
    attntion_output, attention_weights1 = self.mha1(input, mask) 

    # ②エンコーダからの出力をマルチヘッドアテンションで処理
    attntion_output, attention_weights2 = self.mha(attntion_output, encoder_output, mask) 

    # ③ポイントワイズ・フィードフォワード・ネットワーク
    output = self.ffn(attntion_output)

    return output, attention_weights1, attention_weights2
```

以上です。

# まとめ

Transformerの全体図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/d116fa95-f3ad-ffb0-5465-d418f8a34021.png)

エンコーダーの構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/205b43ea-cda3-be59-3499-7c998098f9b5.png)

エンコーダーレイヤー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/91691b5f-00d5-42ad-0fca-b0fc326c0369.png)

デコーダーの構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/af7e7f35-3d71-3dee-cedc-ad06903e2a1d.png)


デコーダーレイヤー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/fdf6fe32-a780-c9fe-9dd9-c0e396fcb702.png)