3秒でわかる
文中の各語が他の語をどれだけ参照すべきかを重みで決める仕組み。Transformerの中核で、長い文脈の理解を支えています。
30秒図解
もう少し詳しく
どういうものか
Self-Attentionは、入力された文の各トークンが、同じ文の中の他のトークンをどれだけ参照するかを重みとして計算し、その重みで情報を集め直す仕組みです。各トークンをQuery、Key、Valueという3つのベクトルに変換し、QueryとKeyの内積で関連の強さを測り、ソフトマックスで正規化した重みをValueに掛けて足し合わせます。自分自身を含む全位置を見るので、Self、つまり自己という名前が付いています。
なぜ必要か
「その本は面白かったので友人に貸した」という文で、「貸した」の目的語が「本」だと判断するには、離れた位置の語を見る必要があります。従来のRNNは前から順に処理して状態を持ち回るため、距離が離れるほど情報が薄れ、しかも順番に計算するので並列化できませんでした。Self-Attentionは全位置の関係を一度の行列演算で求めるので、距離による減衰が無く、GPUで一気に計算できます。この2点が大規模言語モデルを現実的にした転換点です。
具体例
import numpy as np
def self_attention(X, Wq, Wk, Wv):
Q, K, V = X @ Wq, X @ Wk, X @ Wv
d_k = K.shape[-1]
scores = Q @ K.T / np.sqrt(d_k) # 各語と各語の関連の強さ
weights = np.exp(scores) / np.exp(scores).sum(axis=-1, keepdims=True)
return weights @ V # 重み付きで情報を集めるnp.sqrt(d_k) で割るのは、次元が大きいと内積が大きくなりすぎ、ソフトマックスが1点に張り付いて学習が進まなくなるためです。実際のモデルでは、この計算を異なる重みで複数並べるマルチヘッド構成を取り、語の並びの情報は位置エンコーディングで別に与えます。
つまずきやすいところ
計算量が系列長の2乗で増える点が実運用に直結します。文脈を2倍にすると計算とメモリは4倍になり、長文の入力が高価な理由もここにあります。もうひとつ、Self-Attention自体は語の順番を知りません。並べ替えても同じ結果になるため、位置の情報を別に足す必要があります。文章生成では、未来のトークンを見せないマスクを掛ける点も要点です。
似た用語との違い
| 語 | 意味 |
|---|---|
| Self-Attention | 同じ系列の中で参照し合う |
| Cross-Attention | 別の系列を参照する |
| Transformer | Self-Attentionを積み重ねたモデル構造 |