深層学習

Self-Attention

同じ系列の入力をQuery・Key・Valueへ射影し、位置間の類似度でValueを重み付けして各位置の表現を更新する注意機構です。

  • A|中核
  • 深層学習

数式の記号で止まったら 記号の読み方 (∂・⊙・転置・上付き添字を、読み方から)

ひとことで言うと

Self-Attentionは、系列内の各位置が他の位置を参照して、自分の表現を作り直す計算です。同じ入力行列から3種類の線形射影 Q,K,VQ,K,V を作り、QueryとKeyの相性で重みを決め、その重みでValueを加重平均します。入力元が同じ系列なので「self」です。

会議で各人が「自分はいま何を知りたいか」をQuery、「自分はどんな情報を持つか」をKey、「実際に渡せる内容」をValueとして掲示し、QueryとKeyが近い人の発言を強く取り込む仕組みです。探す基準と渡す内容を分けるので、同じ入力から三つの役割を作る意味があります。

なぜ必要か

畳み込みのように近傍を固定せず、再帰のように前の時刻の計算を待たずに、系列内の任意の位置を直接参照できます。たとえば長い距離にある語の関係を、何層も経由せず一度の注意計算で結べます。ここで「入力をそのまま比較する」と考えると実装を誤ります。参照したい条件、照合される条件、返す特徴は用途が違うため、三つの射影を別パラメータで持たせます。

ただし、全位置対全位置を比較する代償があります。系列長を nn、各ヘッドの特徴次元を dkd_k とすると、スコア行列 QKTQK^{\mathsf{T}} は n×nn\times n で、計算量もメモリも系列長に対して二乗で増えます。長文で重くなる原因は、射影そのものよりこの全ペアの行列を作る部分です。

系列長の変化全位置対全位置の組数実装上の影響
nnn2n^2基準
2n2n4n24n^2スコア計算と注意重みの保持が約4倍

仕組み

入力を X∈Rn×dmodelX\in\mathbb{R}^{n\times d_{\mathrm{model}}}、Query・Key・Valueの射影行列を WQ,WK,WVW^Q,W^K,W^V とします。まず同じ XX から次を計算します。

Q=XWQ,K=XWK,V=XWVQ=XW^Q,\qquad K=XW^K,\qquad V=XW^V

nn は系列長、dmodeld_{\mathrm{model}} は入力特徴次元、Q,K,VQ,K,V はそれぞれ検索条件・照合対象・集約する内容です。Q,KQ,K の最終次元を dkd_k、VV の最終次元を dvd_v とすると、計算順は「内積でスコア → スケーリング → マスク → softmax → Valueの加重和」です。

Attention(Q,K,V)=softmax(QKTdk+M)V\mathrm{Attention}(Q,K,V)=\mathrm{softmax}\left(\frac{QK^{\mathsf{T}}}{\sqrt{d_k}}+M\right)V

MM は許可しない対応を表すマスクで、許可位置は0、禁止位置は実質的に −∞-\infty とします。softmaxの前に加えるため、禁止位置の確率が0になります。自己回帰で未来を見せない因果マスク、パディングを無視するマスクはこの場所に入ります。マスクをValueに掛けるだけでは、禁止位置が重み計算に参加してしまうので不十分です。

dk\sqrt{d_k} で割る理由は単なる正規化ではありません。qq と kk の各成分が平均0、分散1で独立なら、内積 q⋅k=∑i=1dkqikiq\cdot k=\sum_{i=1}^{d_k}q_i k_i の分散は dkd_k に比例します。次元が大きいほどsoftmaxに入る値の絶対値が大きくなり、最大要素だけがほぼ1になる飽和が起き、勾配が小さくなります。そこで内積を dk\sqrt{d_k} で割り、スコアの尺度を戻します。分母はsoftmaxの後ではなく前です。

Multi-Head Attentionでは、Q,K,VQ,K,V を一組だけ使うのではなく、ヘッドごとに別の射影を行い、各ヘッドで注意を計算します。ヘッド数を hh とし、通常は dk=dv=dmodel/hd_k=d_v=d_{\mathrm{model}}/h として、各ヘッドの出力を連結してから出力射影を適用します。

headi=Attention(XWiQ,XWiK,XWiV),MultiHead=Concat(head1,…,headh)WO\mathrm{head}_i=\mathrm{Attention}(XW_i^Q,XW_i^K,XW_i^V),\qquad \mathrm{MultiHead}=\mathrm{Concat}(\mathrm{head}_1,\ldots,\mathrm{head}_h)W^O

ヘッドが分けるのは入力系列そのものではなく、特徴空間と相性の見方です。あるヘッドは近い位置、別のヘッドは遠い依存関係というように、異なる射影空間で同時に参照できます。ヘッド数を増やすだけで情報量が増えるわけではなく、総特徴次元との配分が実装上のポイントです。

試験でどう問われるか

問われ方正解に寄る条件引っかけ
Q/K/Vの役割同じ入力から別々に線形射影し、Q-Kで重み、Vで集約Q・K・Vを同じテンソルの別名とする
計算順QKTQK^{\mathsf{T}} → 1/dk1/\sqrt{d_k} → マスク → softmax → VVsoftmax後にスケールする/VV同士を比較する
スケーリングの理由内積の分散が dkd_k に比例し、softmax飽和を招くため出力ベクトルの長さをそろえるためだけとする
Multi-Headの意味射影空間を複数に分け、異なる関係を並列に学習系列を位置ごとに分割する機構とする
マスクの位置softmax前のスコアに加え、禁止位置を確率0にするValueを0にするだけで未来参照を防げるとする
計算量QKTQK^{\mathsf{T}} の n×nn\times n により計算量・メモリが n2n^2 で効くヘッド数だけが長文時の主因とする

実装で確かめる

NumPyで一つのヘッドを実装します。scores の形が系列長の二乗になること、causal maskで未来側の重みが0になることを確認できます。

import numpy as np

rng = np.random.default_rng(0)
n, d_model, d_k, d_v = 4, 6, 3, 2
X = rng.normal(size=(n, d_model))
Wq, Wk, Wv = (rng.normal(size=(d_model, d)) for d in (d_k, d_k, d_v))
Q, K, V = X @ Wq, X @ Wk, X @ Wv
scores = Q @ K.T / np.sqrt(d_k)
mask = np.triu(np.ones((n, n), dtype=bool), k=1)
scores = np.where(mask, -np.inf, scores)
weights = np.exp(scores - np.max(scores, axis=1, keepdims=True))
weights /= weights.sum(axis=1, keepdims=True)
out = weights @ V
print(scores.shape, weights.shape, out.shape)
print(np.round(weights[0], 6))

出力は (4, 4) (4, 4) (4, 2) となり、1番目の位置の重みは [1. 0. 0. 0.] です。softmax前に上三角をマスクしたため、先の位置へ重みが流れません。np.max を引くのはsoftmaxの値を変えずに指数のオーバーフローを避けるためです。

実装では KK の転置を忘れるとスコアの軸が崩れ、マスクの向きを間違えると「過去を見られない」モデルになります。バッチやヘッドを追加した場合も、最後の二軸がQuery位置とKey位置になっているかを形状で確認します。

取り違えやすいもの

用語Self-Attentionとの切り分け
Encoder-Decoder AttentionQは一方の系列、K/Vは別の系列から作る。Self-Attentionは同じ系列から作る
Additive AttentionQとKの相性を小さなネットワークで計算する方式。Scaled Dot-Productは内積を使う
Multi-Head AttentionSelf-Attentionそのものではなく、複数の射影空間で注意を並列化する拡張
Causal Attention自己注意に未来禁止マスクを加えた制約付きの形。全Self-Attentionが因果的とは限らない
Cross-Attention参照元が別系列。Q/K/Vの入力元が同じかどうかで判別する

想起チェック

Q、K、Vはそれぞれ何を決める役割か

Qは探したい条件、Kは照合される条件、Vは重み付けして集約する内容です。三つとも同じ入力から別の射影で作れます。

Scaled Dot-Product Attentionの計算順を答える

まず QKTQK^{\mathsf{T}}、次に dk\sqrt{d_k} で割り、必要ならマスクを加え、softmaxの重みを VV に掛けます。

スケーリング係数で割らないと何が起きるか

内積の分散が dkd_k に比例して大きくなり、softmaxが飽和して勾配が小さくなります。

系列長を2倍にしたとき、Self-Attentionの何が問題になるか

全位置対全位置のスコア行列が必要なので、スコア計算とその行列を保持するメモリが系列長の二乗で増えます。

出典