Self-Attention(+MultiHead)を図・ベクトル（行列）の両方で整理してみた。

#はじめに
Source Target Attentionを前回整理したので、これを前提に次はSelf-Attentionを整理してみます。前回分はこちらです↓ので、見ていただけると嬉しいです。
「Attentionを理解するためにRNN、Word2Vec、LSTM、Seq2Seq、Attentionの順に整理してみた」https://qiita.com/ta2bonn/items/c645ecbcf9dabd0c4778

#参考元
Self-Attentionを整理するに当たり、こちらのサイトを参考にさせていただきました。
https://towardsdatascience.com/illustrated-self-attention-2d627e33b20a

#Self-Attentionとは
まずそもそも何者？から入ります。Source Target Attentionはエンコーダーとデコーダー（inputとmemory）を使用していましたが、Self-Attentionでは自Layer内で全てを完結することで計算を高速化するというものです（input＝memory）。また、並列計算によって出力をより複雑に表現できます。文章だと本当に意味が分からないですよね。これをがんばって整理してみます。

#Source Target Attention　との比較
Source Target AttentionとSelf-Attentionを超ざっくり比較すると↓のとおりです。Source Targetではinputとmemoryを使っていましたが、selfではinputだけです。
またkey、valueはmemoryの代わりにinput全ての単語を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/f1dc84fe-84fd-94ef-cc6e-38afb764bd52.png)


#Self-Attentionのレイヤ
##全体レイヤ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/1c51ce87-a79d-5738-95c2-1d0f67084b7b.png)
もう絵を見ても何のことやら分からないと思うのですが、順番に整理します。
まずインプット文章を「I am man」とします。「何だその文章？」と思われるかもしれませんが、３単語が絵にする限界だったので適当に文章を作っています。ご容赦いただければ幸いです。また、one-hotから分散表現の獲得までは省略します（気になる方は前回投稿を参照くださいhttps://qiita.com/ta2bonn/items/c645ecbcf9dabd0c4778 ）。
Self-Attentionのレイヤを見ると、それぞれの単語から「query、key、value」が作成されていますので、説明はココから始めるとして、以降「Ｉ」の単語を使って説明します。

##最初の単語「Ｉ」に絞ったレイヤ
「Ｉ」に絞ると↓のようなイメージです。ポイントは「Ｉ」から出てるqueryが全ての単語につながっている箇所です。詳細は後で説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/5e94a8e7-d196-3933-bf42-909b7d10ffd4.png)


#Self-Attentionの処理順序
参考元から拝借させていただきました。が、この手順を眺めてもまだ良く分からないと思うので、順番に説明します。参考元と紐づけできるように英語をそのまま書いてますが、日本語「（）」の方を見ていただければＯＫです。
１．Prepare inputs（インプット前処理）
２．Initialise weights（query、key、valueの重み設定）
３．Derive key, query and value（query、key、valueの導出）
４．Calculate attention scores for Input 1（scoreの導出）
５．Calculate softmax（scoreベクトルをsoftmaxで処理）
６．Multiply scores with values（scoreとvalueを分ける）
７．Sum weighted values to get Output 1（計算したベクトルを全部足す）
８．Repeat steps 4-7 for Input 2 & Input 3（全てのインプットに適用）

#Self-Attentionの処理
##１．Prepare inputs（インプット前処理）
ここは先ほど説明を省略するといったone-hotから分散表現の獲得までの処理です。詳細は割愛しますが、↓のとおりになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/bbd729b6-e5d4-0441-520e-3161e1b849c9.png)

##２．Initialise weights（query、key、valueの重み設定）
いよいよSelf-Attentionレイヤの説明に入ります。まず、「query」「key」「value」が何者なのか記載しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/92bda049-0054-609a-5ae3-8fd3e6e9accc.png)
やりたい事は「重み設定」ですので、それぞれに重みwを設けます。重みの数値は適当で列数は自由に設定可能です（ここでは３列）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/04c456cc-bc65-1766-fd36-5406d3ec2710.png)
＜ポイント＞
源泉となるデータは同一のinputですが、重み(w)はそれぞれで用意する所です。

##３．Derive key, query and value（query、key、valueの導出）
###keyの導出
それぞれの単語に重みを掛けて、keyベクトル（行列）を作成します。以降の処理で全ての単語ベクトル（key1,key2,key3）を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/a6f7027a-e7b6-655b-0ad5-7264f33e9dcc.png)
###queryの導出
keyと同様に計算します。ですが、今は「Ｉ」の処理なので、queryは「Ｉ」の部分（query1）しか使いません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/2dc15135-655a-6886-02ff-c61dc319eb9e.png)
###valueの導出
keyと同様、以降の処理で全ての単語ベクトル（value1,value2,value3）を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/c7c78c22-dde3-4874-915a-64fd689968d8.png)


##４．Calculate attention scores for Input 1（scoreの導出）
これがAttention_Weightになる元のベクトルです。queryとkeyから「Ｉ」と「全単語」の関係性を取得します。実際の次元数は√dになりますが、一旦無視します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/814ebee7-5167-dd98-1551-6fc2ce0e3476.png)


##５．Calculate softmax（scoreベクトルをsoftmaxで処理＝Attention_Weightの生成）
ここは単純にscoreベクトルをsoftmaxで計算しただけです。これがAttention_Weightです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/277fdbb5-168e-bf78-746d-7617b0aac3ac.png)

##６．Multiply scores with values（scoreとvalueを分ける）
上記５でAttention_Weightを取得したので、valueから単語を抽出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/efff330d-bdc8-75e3-d1eb-97a5760dfb13.png)

##７．Sum weighted values to get Output 1（計算したベクトルを全部足す）
valueから単語情報を抜き出したら、全てのベクトルを足します。これがoutputで、「I」が他のどの単語と関係が深いのかが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/1e94fc60-c6a4-55bd-9411-9007d45a52e8.png)
ただ、今回の例では非常に分かりにくいので、論文「Attention Is All You Need」＝Transformer　から絵を拝借させていただきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/31228da5-ed0a-5635-ae9e-fc5c18316427.png)
上の絵は上段がqueryです。queryである「its」が Law, application という
valueから情報を引いていることを示しています。

##８．Repeat steps 4-7 for Input 2 & Input 3（全てのインプットに適用）
上記４～７を他の単語にも適用すると以下のとおりになります。が、今回の例では良く分からない数字（値）になってますね。すみません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/02f5737f-be47-a984-69ce-9d00acb74859.png)
＜参考：「am」のイメージ＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/761ef4db-f627-c362-452c-7d4a8624fba5.png)
＜参考：「man」のイメージ＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/8eda2785-5cf3-a74f-e6ff-88b652b7fb9d.png)

#Self-Attentionをベクトル（行列）で整理
ここまで考え方・理屈を中心に整理しましたが、実際にベクトル（行列）で整理すると理解が深まるので、ベクトル（行列）で整理してみました。↓は「Ｉ」の処理です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/5336a6ef-9a84-a3da-a1c5-b0322636f527.png)
＜補足＞
score計算に内積を計算する必要があるため、 queryとkeyの次元数は常に同じでないとダメです。一方、valueの次元数はquery、keyと合わせる必要がなく、outputの次元数になるので、outputを意識した次元数にする必要がある（↑ではquery、keyに合わせているように見えてしまってます。すみません）。つまり「query、key」とvalueでは同じ単語でも異なるベクトル（行列）で表現することが可能です。

#MultiHead
##MultiHeadとは
話を冒頭の「Self-Attentionとは」に戻します。Self-Attentionのメリットとして「並列計算によって、出力をより複雑に表現できる」と書きました。これを実現するのが「MultiHead」です。MultiHeadは一言で言うと「Self-Attentionをいっぱい作って、より複雑に表現しよう」というものです。

そもそも何故こんな事が必要かというと、自然言語処理（NLP）には厄介な問題があって、その一つが「単語間の関係性が複数ある」ことです。

例えば「青が一番好き」と「その服に一番合う色は青」では「一番」と「青」の関係性が異なります。これを同じAttention_Weightで表現すると事実と異なる解釈をしてしまいます。よって、Self-Attentionを複数用意（MultiHeadに）することにより複数の単語関係を理解させます。

##MultiHeadのレイヤ
全体レイヤのイメージは↓のとおりです。今回は3Headにしました。Self-Attention1が今まで説明してきたSelf-Attentionだと理解してください。そうすると2,3が追加されていますよね。これは「単語の関連を今まで１種類で表現していたが、３種類で表現している」ことになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/69039ab9-edb6-1914-ec1d-1642e1e9980b.png)

##MultiHeadのoutput算出方法
それぞれのSelf-Attentionからoutputを得ます。くどいようですが、今まで説明してきたSelf-AttentionはSelf-Attention1です。よってアウトプットは「output1-1」「output2-1」「output3-1」になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/c7b47906-0cf4-5853-2df6-2f604285f238.png)

各Self-Attention（各head）のoutputが出そろったら、concatenateします。これにアウトプット用の重みw(o)を掛け合わせて、出力を得ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515235/1ee00035-4752-6bda-d25c-62f3b40ce6c3.png)
やっぱり３次元程度だと見た目からでは意味が分からないですが、Attentionは概ね理解できました。

#次回に向けて
次は論文「Attention Is All You Need」＝Transformer　を整理します。

「Attention Is All You Need = Transformer　をざっくり理解してみる。」
https://qiita.com/ta2bonn/items/4ec687bc136a41c364ae