Attention Is All You Need = Transformerをざっくり理解してみる。

#はじめに
前回までにAttentionを整理したので、論文「Attention Is All You Need」=Transformerに挑戦しようと思います。ベクトル（行列）、コーディングレベルでの整理はできていません( ;∀;)
本文中では「Attention Is All You Need」で説明しているモデルをTransformerと記載します。Attentionが分かる前提で記載しておりますので、Attentionを知りたい方は過去分を読んでいただけると嬉しいです。

##過去分
過去分はコチラ↓
①【Source Target Attention】
「Attentionを理解するためにRNN、Word2Vec、LSTM、Seq2Seq、Attentionの順に整理してみた」
https://qiita.com/ta2bonn/items/c645ecbcf9dabd0c4778 

②【Self Attention】
「Self-Attention(+MultiHead)を図・ベクトル（行列）の両方で整理してみた。 」
https://qiita.com/ta2bonn/items/60601d18db57bd98d142

#参考元
論文「Attention Is All You Need」
https://arxiv.org/pdf/1706.03762.pdf

Qiita「計算量オーダーについて」
https://qiita.com/asksaito/items/59e0d48408f1eab081b5


#概略
過去のRNN、Encoder・Decoderモデル（過去分①参照）は、単語を逐次的に処理するため並列処理ができず、計算量が膨大になっていました。計算量を押さえようとすると（例：RNN⇒CNNにする）、長文の単語依存関係を捉える事が難しくなるという課題があり、その課題を解決するために登場したのがTransformer。
Self Attentionを使うことで計算量を抑え（※）、かつ長文の単語依存関係も表現する事が可能になりました。
（※）今までの時間計算量Ｏ(N)またはＯ(logN)　⇒　O(1)に短縮

#ちょっと寄り道（時間計算量「Ｏ」）
よく混乱してしまうので、ここで整理しておきます。備忘的な位置づけなので飛ばしてもらって問題ございません。整理にあたり、Qiita「計算量オーダーについて」https://qiita.com/asksaito/items/59e0d48408f1eab081b5 をめちゃくちゃ参考にさせていただきました。

###説明
時間計算量を表す記票方法をO記法という。O記法とは特定のアルゴリズムでの計算が、どれくらい掛かるかを表した記号であり、処理時間が短い順（性能が良い順）に以下のとおり。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/467e4f44-e2b8-1cd6-4c54-ac20aa2c3893.png)

#Transformer全体構成
以下のとおりです。これを順番に見ていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/fb9ce37b-0440-9c43-4db5-c19e87fd3a55.png)
【ポイント】
Transformerのポイントは以下の４点だと思っています。複雑なので読みほどく中で説明していきます。
　①　全体構成はEncoder-Decoderモデル（左がEncoder、右がDecoder）
　②　Positional_Encodingによる文章の順序把握
　③　３種類の縮小付Attention(※)を活用
　　　　全体構成：Source-Target_Attention
　　　　Encoder：Self_Attention
　　　　Decoder：Masked-Self_Attention
　　　　(※)縮小付Attentionについては後述します。
　④　Encoder、Decoder共に６層構造

#Encoder（左側の部分）
##１．Positional_Encoding（位置エンコード）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/4a2f173a-e887-2c45-647e-825b994b30b6.png)
Attentionは単語の順番（位置関係）を認識できないので、文章の意味（文脈）を正確に解釈できないという問題があります。よって、TransformerではPositional_Encoding（位置エンコード）を使用する事でこの問題を解決しています。
仕組みは、単語の分散表現（Input Embedding）に単語の位置情報（一意の値）を加算するというもの。
Transformerは、この単語の位置情報（一意の値）にsin関数とcos関数を使っており、このsinとcosの波形を学習する事で単語の位置関係を把握しています。論文中の数式は以下のとおりですが、難しいので「位置エンコードの考え方」でもう少し詳しく書きます。

＜式＞　pos：位置、　ｉ  ：次元
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/f8070c9a-8493-55ff-4d7d-579d9921d774.png)


###位置エンコードの考え方
以下を参考にさせていただきました。
■位置エンコーディングについて
https://scrapbox.io/nishio/%E4%BD%8D%E7%BD%AE%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0
■ベクトルの回転
https://www.buildinsider.net/small/bookkinectv2/0803

上記を元に整理します。
位置エンコードを表現する際にsin、cosを使用することで、位置表現を「回転行列」で表すことができ、異なる回転周期をいくつも入れることで単語間の曖昧さを許容できるようになるとのこと。参考元を引用させていただき、２次元で整理します。
①　まず下のようなベクトルｖがあるとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/1dfa93a3-47f5-922e-5e8d-8dd337412d00.png)

②　ｖをcos、sinで表現すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/b1ebb02c-759e-ff15-ebb9-5884ae3986bd.png)
③　このｖをθだけ回転（１行目のφ ⇒ φ+θ）させるとベクトルR(v)は三角関数の加法定理から以下のとおり（2行目の変換）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/18c292af-f9e7-e351-87c4-bd29ed5f2bdc.png)
　　　　　　　　　　　　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/2d85e71c-f56e-6653-777b-129113aa25cf.png)
④　これを行列で表現すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/a291bb52-6bb0-7637-7245-5979c54bb8b1.png)
⑤　よってvをθだけ回転させた行列R(v)（＝求めるべき（学習するべき）行列）は以下のとおりとなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/09e6bdac-ac2c-0847-d252-6e84a828329e.png)
⑥　最後にこのベクトルを位置情報としてInput_Embeddingに加算する。
　　⇒concatではなく加算で上手くいくらしい。

## ２．Multi-Head_Attention（Self_Attention）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/40816d87-fb86-f48a-27fa-f00d89c30782.png)
### やりたい事
input文章に対する単語間の依存関係をSelf_Attentionで表現させ、単語の位置情報を含めて正規化する。

### 詳細
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/a06ca517-ab1c-47b0-adff-48d4c643f25f.png)
「Multi-Head Attention」の仕組みは前回（過去分の②【Self Attention】）で説明しているので割愛します。Transformerに内臓するSelf-Attentionを論文では「Scaled Dot-Product Attention」＝縮小付内積Attention　と呼称しています。
Scaled Dot-Product Attentionは、query、keyの次元をd_k、valueの次元をd_vとした時、下記の式で表される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/c3328577-7b84-8b11-c9ee-81acea09d727.png)
つまり、通常はqueryとkeyの内積（Attention_Weight）を計算する際、そのままの次元数で計算するが、Transformerではqueryとkeyの内積（Attention_Weight）算出時に√d_kで割る（縮小する）というもの。さらに、論文中にhead=8との記載があるので、Multi_Headのhead数を８つとしてquery,key,valueの重みを使い算出している。式は以下のとおり。重ねてになりますが、MultiHeadの詳細は「過去分の②【Self Attention】」を参照いただければと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/04a28d0c-9eb0-da95-1ce5-6067e6f10fa4.png)
### Add & Norm
TransformerのNormalizationは「Layer Normalization」を使用しており、inputの１文単位に正規化している（１文が100単語の場合、100単語で正規化）。Positional_Encodingの結果を『Ｅ』、Multi-Head_Attentionを『Ｍ』とするとLayer Normalization『Ｌ』は以下のとおり。
　　　　　　　　　Ｌ＝ Layer Normalization（Ｅ＋Ｍ）

## ３．Feed_Forward
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/b779534c-6162-cdc1-6bd7-b2940662cd5d.png)
Feed_ForwardはPosition-wise 順伝播ネットワーク。
Position-wiseの意味は「単語毎にニューラルネットワークがある」という意味で、ニューラルネットワーク内では他単語との干渉はありません。ただし、計算に使用する「重み」は全単語共通のものを使用しています。なお、2層のニューラルネットワークになっていて、活性化関数はReLUを使用しています。式は以下のとおり。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/e75b62af-e777-4f2f-ddd1-c079256aedc1.png)
### Add & Norm
Feed_Forwardを『Ｆ』とすると、Feed後のLayer Normalization『ＦＬ』は以下のとおり。
　　　　　　　　　ＦＬ＝ Layer Normalization（Ｌ＋Ｆ）
#　Decoder（右側の部分）
## ４．Positional_Encoding（位置エンコード）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/770bfc3e-e752-7468-2cfa-335b5acbf56a.png)
Encoderと同様なので説明を割愛します。
## ５．Masked Multi-Head_Attention（Self_Attention）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/af0e86e6-19fc-c774-82f8-81ed58667cd1.png)
通常のMulti-Head_Attentionと基本的には同じ。ただし、decoderでは学習のカンニングを防ぐため、自単語より先（文章の右側）の情報をマスキングして（隠して）学習させる。
## ６．Multi-Head_Attention（ Source Target Attention ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/1ac21ad7-5f62-6422-2503-101a6624bf2f.png)
ここはSource Target Attention。t時刻の文字からt+1時刻の文字を導出。
　quary　⇒　Outputs(Decoder)から入力するベクトル（行列）
　key, value(memory)　⇒　Inputs(Encoder)から入力するベクトル（行列）
## ７．Feed_Forward
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/95d7ffcd-0555-3980-cb70-b5f91ed549ea.png)
Inputs(Encoder)と同様。ただしFeedForward層のニューラルネットワークに使用する重みWは、モデルの最下段にあるEmbeddingに使用する重みと同一のものを使用します。
## ８．Output
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/49985452-c813-e26c-a9a7-03dfec14c293.png)
FeedForward層のニューラルネットワークから出力した単語をSoftmaxで計算し、最も確率の高い単語を出力します。原理はseq2seqと同様。
#Transformer全体構成（再び）
今まで説明してきた機能を一つの流れとして、コレをEncoder、Decoder共に６層構成でやったものが真のTransformerです。
##Encoderの６層構造
まずはEncoderです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/fb34324e-7203-3aec-a98c-fb5e867545e4.png)

##Decoderの６層構造
次にDecoderです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/c09d8b01-2283-97bb-1caa-903348df5c32.png)


ここまで複雑にする事で、精度を向上させていると思われます。スゴイ。

#次回
BERTの論文に挑戦したいなぁ。