一文要約: Multi-Head Attention は射影後の幅を複数の小さなヘッドに整理し、各ヘッドに固有の Q・K・V の視点を与えます。最後に結果を連結し、
W_Oで混ぜ合わせます。各ヘッドが何を学ぶかは事前に割り当てられるのではなく、訓練によって決まります。
11.1 なぜ複数のヘッドが必要なのか
11.1.1 単一ヘッドの限界
第10章では Attention の完全な計算を扱いましたが、それは 単一ヘッドの Attention でした。Query-Key のスコアマップと Value の混合結果が一つずつです。
単一ヘッドでも複雑な関係は表せるため、「一つのパターンしか学べない」という言い方は強すぎます。より正確な制約は、その層に Q・K・V の射影视点が一組しかなく、すべての関係が同じマッチング空間と混合空間を共有することです。
次の文を見てみましょう:
「蒔絵師は硯箱にひびが入ったと気づき、それを棚へ戻した。」
この文を完全に理解するには、いくつかの種類の関係を同時に追跡する必要があります:
- 構文的: 「戻した」の動作主は「蒔絵師」
- 共参照: 「それ」は前の「硯箱」を指す
- 位置・句構造: 「棚へ」が「戻した」に結びつく
- 因果・時間的: ひびに気づいたことが、その後の動作につながる
複数のヘッドは、こうした関係を異なる部分空間で表す余地を与えます。ただし、各ヘッドが必ずきれいな「構文担当」「共参照担当」に分かれるわけではありません。
11.1.2 解決策: 複数のヘッドを並列に
Multi-Head Attention の核心は、より狭い Attention 計算を複数並列に実行し、異なるマッチングや情報経路を学べるようにすることです。
Head 1: 構文構造に注目するかもしれない (主語-動詞-目的語)
Head 2: 共参照に注目するかもしれない (代名詞と名詞)
Head 3: 局所的な近接性に注目するかもしれない (隣接トークン)
Head 4: 意味的類似性に注目するかもしれない (関連概念)
...
その出力を連結し、W_O が各ヘッドの次元をどう混ぜるかを学習します。
11.1.3 アナロジー
一枚の絵を分析する場面を想像してください。一組の目なら色だけに注目するかもしれません。複数の目があれば、色、形、質感、構図を同時に見る余地が生まれます。Multi-Head Attention も同じように複数の視点を持ちますが、何を見るかは手作業で決めるのではなく学習されます。
11.2 ヘッドへの分割
11.2.1 次元の分割
鍵となる操作は、各結合射影の最後の次元を、ヘッド軸とヘッド幅へ reshape することです。生の token embedding を無造作に切るのではなく、Q・K・V はすでに学習可能な射影を通っています。
K (Key) を例として、以下の設定で考えます:
d_model = 512num_heads = 4- この古典的な等幅の例では
d_head = d_k = d_v = d_model / num_heads = 512 / 4 = 128
分割は次のように展開されます:
結合 K: [batch_size, seq_length, num_heads × d_k]
= [4, 16, 512]
↓
reshape: [batch_size, seq_length, num_heads, d_k]
= [4, 16, 4, 128]
↓
転置: [batch_size, num_heads, seq_length, d_k]
= [4, 4, 16, 128]
11.2.2 なぜ転置するのか
転置によって num_heads を第2軸に移動させ、形状を [batch, num_heads, seq_len, d_k] にします。これは次のことを意味します:
- バッチ内の各シーケンスについて
num_heads個の独立した Attention 計算を持つ- それぞれが
seq_len個の位置を処理する - 各 Query / Key の位置は
d_k次元のベクトルを使う
このレイアウトなら、一つの batched tensor 演算で全ヘッドを並列計算できます。スコア計算では別々の slice を使いますが、ヘッド同士は孤立した小さなモデルではありません。W_O、residual path、共通の loss を通じて一緒に学習されます。
11.2.3 同じ分割を Q、K、V に適用する
Q: [4, 16, 512] → [4, 4, 16, 128] # d_k
K: [4, 16, 512] → [4, 4, 16, 128] # d_k
V: [4, 16, 512] → [4, 4, 16, 128] # d_v
これでヘッド別の (Q, K, V) が 4 組揃い、並列計算の準備ができました。
11.2.4 二つの等価な実装
余分な head 間構造がなければ、小さな行列を出力次元に沿って連結すると一つの結合行列になります。そのため、次の二つの見方は数学的に等価です:
概念的な見方: 各ヘッドが W_i^Q、W_i^K、W_i^V という射影 slice を持ち、[d_model, d_k] の W_i^Q を使って Q_i = X @ W_i^Q を計算する。
実用的な見方: 一つの結合 W_Q が Q 全体を生成し、最後の次元を num_heads 個の slice へ reshape する。
実際の実装では実用的な見方を採用します。なぜなら、一つの大きな行列乗算のほうが、多数の小さな乗算よりも GPU 効率が良いからです。GPU は多数の小さく散らばった演算よりも、大きく連続した演算を好みます。
11.3 すべてのヘッドを並列に計算する
11.3.1 各ヘッドが自分のスコアマップを計算する
分割後、すべてのヘッドが同じ Attention の式を独立に実行します:
各ヘッド h = 1, 2, 3, 4 について:
scores_h = Q_h @ K_h^T [4, 16, 128] @ [4, 128, 16] = [4, 16, 16]
weights_h = softmax(scores_h / sqrt(d_k) + M_h)
output_h = weights_h @ V_h [4, 16, 16] @ [4, 16, 128] = [4, 16, 128]
11.3.2 次元の追跡
一つのヘッドにおける Q @ K^T:
Q: [4, 4, 16, 128]
batch heads seq d_k
K^T: [4, 4, 128, 16]
batch heads d_k seq
Q @ K^T: [4, 4, 16, 16]
batch heads seq seq
Softmax(Q @ K^T / sqrt(d_k) + M) @ V:
Attention Weights: [4, 4, 16, 16]
batch heads seq seq
V: [4, 4, 16, 128]
batch heads seq d_v
Output: [4, 4, 16, 128]
batch heads seq d_v
11.3.3 並列化が得るもの
総幅を固定すると、4 ヘッドへ分けても QK^T や weights @ V の主な乗加算量が4倍になるわけではありません。各ヘッドが狭く、その幅の合計が 512 に戻るからです。利点は、複数のスコアマップと Value 経路を持てることです。各ヘッドがきれいに専門化する保証ではありません。
11.4 ヘッドを統合して戻す
11.4.1 連結 (Concat)
すべてのヘッドが出力を計算した後、それらを連結して完全なモデル次元に戻します:
ヘッド出力: [4, 4, 16, 128]
batch heads seq d_v
↓
転置: [4, 16, 4, 128]
batch seq heads d_v
↓
連結: [4, 16, 512]
batch seq d_model
連結操作は最後の二つの次元をまとめるだけです。この例では 4 ヘッド × 128 次元 = 512 次元になります。
11.4.2 出力射影 W_O
連結は機械的な操作で、各ヘッドの出力を隣に並べるだけです。次元間を混ぜるのが W_O です:
A @ W_O
[4, 16, 512] @ [512, 512] = [4, 16, 512]
W_O は学習される射影行列です。その役割は:
- ヘッド間で情報を混合する。各ヘッドが学んだことが他のヘッドに影響を与えられるようになる
- 連結された表現を統一された空間に射影する
- 各ヘッドの貢献度をどのように重み付けするかをモデルに決定させる
11.4.3 なぜ W_O が重要なのか
W_O の前では、連結ベクトルの各 slice は一つのヘッドから来ています。W_O は全ヘッドの次元から学習可能な組み合わせを作り、Attention 分岐を residual stream へ返します。
11.5 出力の比較: W_O の前と後
11.5.1 A と A @ W_O
W_O 適用前 (A):
- 形状: [16, 512]
- 値: すべてのヘッドの出力ベクトルを生のまま連結したもの
W_O 適用後 (A @ W_O):
- 形状: [16, 512]
- 値: 混合され射影された表現
形状は同じでも中身は異なります。W_O 適用後の tensor は Attention 分岐の出力で、residual stream と合流します。LayerNorm がサブレイヤーの前か後かは、pre-norm / post-norm の設計によって変わります。
11.6 Multi-Head Attention の全体フロー
11.6.1 エンドツーエンド
入力 X [batch, seq, d_model]
↓
Q, K, V を生成 (W_Q, W_K, W_V 経由)
↓
ヘッドへ reshape [batch, num_heads, seq, d_head]
↓
ヘッドごとに独立に Attention を計算
↓
連結 [batch, seq, d_model]
↓
出力射影 (@ W_O)
↓
出力 [batch, seq, d_model]
11.6.2 PyTorch 実装
import torch
import torch.nn as nn
import torch.nn.functional as F
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
if d_model % num_heads != 0:
raise ValueError("d_model must be divisible by num_heads")
self.d_model = d_model
self.num_heads = num_heads
self.head_dim = d_model // num_heads
# この例では d_k = d_v = head_dim
self.W_Q = nn.Linear(d_model, d_model)
self.W_K = nn.Linear(d_model, d_model)
self.W_V = nn.Linear(d_model, d_model)
self.W_O = nn.Linear(d_model, d_model)
def forward(self, x, allowed_mask=None):
batch_size, seq_len, _ = x.shape
# 1. Q, K, V を生成
Q = self.W_Q(x) # [batch, seq, d_model]
K = self.W_K(x)
V = self.W_V(x)
# 2. ヘッドに分割
Q = Q.view(batch_size, seq_len, self.num_heads, self.head_dim)
K = K.view(batch_size, seq_len, self.num_heads, self.head_dim)
V = V.view(batch_size, seq_len, self.num_heads, self.head_dim)
# 転置: [batch, num_heads, seq, head_dim]
Q = Q.transpose(1, 2)
K = K.transpose(1, 2)
V = V.transpose(1, 2)
# 3. ヘッドごとの Attention
scores = torch.matmul(Q, K.transpose(-2, -1)) / (self.head_dim ** 0.5)
if allowed_mask is not None:
# [batch, heads, query_len, key_len] へ broadcast 可能
scores = scores.masked_fill(~allowed_mask, float('-inf'))
attention_weights = F.softmax(scores, dim=-1)
attention_output = torch.matmul(attention_weights, V)
# 4. ヘッドを統合
attention_output = attention_output.transpose(1, 2) # [batch, seq, heads, head_dim]
attention_output = attention_output.contiguous().view(
batch_size, seq_len, self.d_model
)
# 5. 出力射影
output = self.W_O(attention_output)
return output
11.7 重要な数値
11.7.1 パラメータ数
Multi-Head Attention には 4 つの重み行列があります:
| 行列 | 形状 | パラメータ数 |
|---|---|---|
| W_Q | [d_model, d_model] | d_model² |
| W_K | [d_model, d_model] | d_model² |
| W_V | [d_model, d_model] | d_model² |
| W_O | [d_model, d_model] | d_model² |
4 つの射影の重みだけを数えると、合計は 4 × d_model² です。bias を使うなら 4 × d_model を加えます。MQA や GQA のように射影幅が異なる構成は第23章で扱います。
GPT-2 Small (d_model = 768) では、4つの重みに 4 × 768² = 2,359,296 個あります。QKV と出力の bias も含めると 2,362,368 個で、Attention レイヤーあたり約 236 万です。
11.7.2 一般的な構成
| モデル | d_model | num_heads | 古典的 MHA の d_head |
|---|---|---|---|
| GPT-2 Small | 768 | 12 | 64 |
| GPT-2 Medium | 1024 | 16 | 64 |
| GPT-2 Large | 1280 | 20 | 64 |
| GPT-3 | 12288 | 96 | 128 |
| LLaMA-7B | 4096 | 32 | 128 |
この表ではヘッド幅が 64 または 128 ですが、これは各モデルの設計選択であり、普遍的な法則ではありません。現代の構成では Query ヘッド数と Key/Value ヘッド数を分けることもあります。
11.8 ヘッドは実際に何を学習するのか
11.8.1 研究で観察されたパターン
BERT を分析した研究では、固定 offset、delimiter、構文、共参照などのパターンが観察される一方、同じ層の複数ヘッドが似た振る舞いをすることも報告されました。次の表は学習後に現れうるパターンであり、head 番号に事前配分された役職ではありません(Clark et al., 2019)。
| ヘッドのタイプ | パターン | 例 |
|---|---|---|
| 位置的 | 近くの固定オフセットに注目する | 常に 1 つ前の位置を見る |
| 構文的 | 主語-動詞-目的語を追跡する | 動詞がその主語に注目する |
| 意味的 | 関連する概念をグループ化する | 同義語が互いに注目する |
| 共参照的 | 代名詞の参照を解決する | 「それ」が指す名詞に注目する |
| 区切り | 文の境界を追跡する | 句読点に注目する |
11.8.2 実用的な例
直感のために、先ほどの蒔絵の文で次のようなパターンを想像してみます。特定モデルを測定した結果ではありません。
Head 1 (位置的): 「戻した」は近くの「それ」に重みを置く
Head 2 (構文的): 「戻した」は動作主の「蒔絵師」に重みを置く
Head 3 (意味的): 「ひび」と「硯箱」が情報を交換する
Head 4 (共参照的): 「それ」は「硯箱」に重みを置く
11.8.3 ヘッドの冗長性
すべてのヘッドが等しく重要とは限りません。Michel らは、評価した翻訳モデルと BERT タスクでは、テスト時に多くのヘッドを除いても指標が有意に低下せず、一つのヘッドだけに減らせる層もあると報告しました(Michel et al., 2019)。これはモデルとタスクに依存する冗長性の証拠であり、すべての Transformer で大半のヘッドが不要だという意味ではありません。
11.9 Multi-Head と Single-Head の比較
11.9.1 計算量の比較
d_model = 512、num_heads = 8、古典的な等幅 MHA で d_head = 64 の場合:
単一ヘッド (幅 512):
- Q @ K^T: [seq, 512] @ [512, seq] → O(seq² × 512)
8 ヘッド (各幅 64):
- 各ヘッド: [seq, 64] @ [64, seq] → O(seq² × 64)
- 合計: 8 × O(seq² × 64) = O(seq² × 512)
QK^T の項だけを見れば、乗加算の合計は同じです。weights @ V も同様です。総射影幅を固定すれば、ヘッド数を増やすだけで QKV や W_O の主要計算が増えるわけではありません。ただし実際の実行時間は kernel、メモリ配置、hardware にも左右されます。
11.9.2 なぜもっとヘッドを増やさないのか
この固定 d_model・等幅の設定では、ヘッドを増やすとヘッド幅が小さくなります:
d_head = d_model / num_heads
d_head が小さすぎると、各ヘッドが有用な部分空間を表す次元が不足する可能性があります。64 や 128 は上表の古典的モデルが選んだ値であり、普遍的な最適値ではありません。構成と実験で決める trade-off です。
11.10 第3部の途中まとめ
Multi-Head Attention の構造はここまでで組み上がりました。第3部にはまだ第12章があり、Attention の出力と、訓練で更新される parameter を切り分けます。ここまでの流れを振り返ります:
| 章 | テーマ | 中核となるアイデア |
|---|---|---|
| 第8章 | 線形変換 | 線形写像、内積、cosine、射影の区別 |
| 第9章 | Attention の幾何 | 学習された Q-K 内積による適合度スコア |
| 第10章 | Q, K, V | 3 つの役割と完全な計算 |
| 第11章 | Multi-Head | 並列の視点。連結と W_O |
Multi-Head Attention の完全な式:
ここで:
章末チェックリスト
この章を読んだ後、あなたは次のことができるはずです:
- 単一の Attention ヘッドに限界がある理由を説明できる。
- 古典的な等幅 MHA で
d_head = d_model / num_headsを導出できる。 - 分割、計算、統合を通じた次元の変化を追跡できる。
- 連結後に
W_Oが何を行うかを説明できる。 - 異なるヘッドが学習しうるパターンの種類を説明できる。
次の章でお会いしましょう
第12章は、forward pass で生まれる hidden state、embedding parameter table、backpropagation が更新する model parameter という、混同しやすい三つを分けて考えます。
ここまでお疲れさまでした。複数のヘッドという考え方が、最初は抽象的に見えても、次元の流れを一度追ってしまえばすっと腑に落ちるはずです。次の章でまたお会いしましょう。