一文でまとめると:Attentionは順伝播中に埋め込みテーブルを書き換えるのではありません。Vを混ぜて、現在の文脈に応じた一時的な表現を作ります。学習時にパラメータが変わるのは、損失、逆伝播、オプティマイザによる更新まで終わったあとです。
12.1 今日はとても軽い章です
今日はとても軽い章です。そして、Attentionの仕組みを締めくくる章でもあります。
前章ではMulti-Head Attentionを複数のヘッドに分け、それぞれが独立して計算するところまで見ました。残る疑問は二つです。
- 各ヘッドの結果を、どうやって一つに戻すのか?
- Attentionの出力は、いったい何を変えているのか?
二つ目が特に混同しやすいところです。私も最初に学んだとき、次の二つを同じ出来事だと思っていました。
- 今処理している文の中で、Tokenの表現が変わること
- モデルファイルに保存された埋め込みパラメータが変わること
これは別の出来事です。
前者は順伝播のたびに起こります。後者が起こるのは学習時だけで、逆伝播が勾配を計算し、オプティマイザが更新を実行したあとです。
この境界が見えれば、QKV、残差接続、そして学習の流れが一本につながります。
12.2 Aにもう少し正確な名前を付ける
これまでは説明を簡単にするため、Attentionの結果をAと書いてきました。しかし資料によっては、AがAttentionの重みを指すこともあれば、Vを混ぜたあとの出力を指すこともあります。
この章では二つを分けます。
ここで:
- PはAttentionの重み
- MはMaskで、遮られた位置はSoftmax後に重み0になる
- H_headsは各ヘッドがVを重み付きで混ぜたあとの出力
つまり、Q×Kを計算しただけで、すぐに「パーセンテージ」が出るわけではありません。正しい順序は次の通りです。
- QKᵀで生の適合度スコアを作る
- √d_kで割ってスケーリングする
- Maskを加える
- Softmaxを通し、各行の和が1になる重みPを得る
- Pを使ってVの重み付き和を取る
この重みは、「Vを混ぜるときに各位置をどれだけ使うか」と考えると分かりやすいです。ただし、意味関係についてモデルが下した厳密な確率判断ではありません。
12.3 H_headsの形:4次元でも怖くない
これまでの例をそのまま使います。
H_heads: [4, 4, 16, 128] │ │ │ └── 各ヘッドの出力次元 │ │ └────── Queryの系列長 │ └────────── ヘッド数 └───────────── バッチサイズ
四つの次元は、それぞれ次を表します。
- バッチに4つの系列がある
- 各系列に4つのヘッドがある
- 各ヘッドは16個のQuery Tokenそれぞれに出力を作る
- 各Tokenは、そのヘッドから128次元の結果を受け取る
通常のSelf-Attentionでは、Query、Key、Valueの系列長が同じなので、Pの形は次のようになります。
[batch, heads, seq_len, seq_len]
ただし、頭の中では二つの長さを別の名前で覚えておくほうが安全です。
[batch, heads, query_len, key_len]
そうしておけば、Cross-AttentionでQueryとKeyの長さが違っても不思議に感じません。
12.4 Concatenate:複数のヘッドを一つに戻す
12.4.1 結合操作
Concatenateは、各ヘッドの次元をもう一度横に並べる操作です。
結合前: [4, 4, 16, 128] 順序を変更: [4, 16, 4, 128] 結合後: [4, 16, 512]
実装では、適当な二つの次元をそのまま潰すわけではありません。先にToken次元とHead次元を正しい順序に並べ、それからreshapeします。
一つのTokenは、4つのヘッドにそれぞれ128次元を持っていました。結合すると、再び一つの512次元ベクトルになります。
12.4.2 なぜ分けてから、また結合するのか?
これは私も最初によく分かりませんでした。ベクトルを分け、別々にAttentionを計算し、最後にまたつなぐ。なぜそんな回り道をするのでしょう?
各ヘッドは射影パラメータの異なる部分を使うため、異なる表現部分空間でAttentionを計算できます。学習後のヘッドの中には、位置、構文、ある特定の関係に強く反応するものもあります。ただし役割を人間が先に割り当てるわけではなく、すべてのヘッドがきれいに名前を付けられる役割を持つ保証もありません。
結合することで、こうした異なる部分空間の結果を一つのToken表現に戻します。
12.5 W_O:結合した結果をどう組み合わせるか学ぶ
Concatenateは、各ヘッドの結果を隣に並べるだけです。それらの特徴をどう組み合わせるかまでは決めません。その役目を持つのが出力射影W_Oです。
今の等幅の例では:
Concatenate後: [batch, 16, 512] W_O: [512, 512] H_attn: [batch, 16, 512]
W_Oは学習可能なパラメータです。4つのヘッドを単純平均するのではなく、それぞれが運んできた特徴をどう再構成するか学習します。
h×d_vがd_modelと等しくない場合、W_Oの一般的な形は次の通りです。
[h × d_v, d_model]
したがって、W_Oが512×512なのは、今の等幅の例に限った話です。
12.6 QKとVは、それぞれ何をしているのか?
12.6.1 QKᵀが混ぜ方を決める
一つのヘッドだけを見ると:
Q: [query_len, d_k] K: [key_len, d_k] QKᵀ: [query_len, key_len]
QKᵀの一つ一つの要素は、あるQuery位置とあるKey位置の適合度スコアです。スケーリング、Mask、Softmaxを通して初めてAttentionの重みになります。
12.6.2 Vが混ぜる内容を運ぶ
Vは「元の文字」そのものではなく、埋め込みをそのまま置いたものでもありません。現在の層への入力XをW_Vで射影した特徴です。
そして:
各Query位置の出力は、複数のVベクトルの重み付き和です。
最短で覚えるなら:
- QとKが「どの位置から、どれだけ取るか」を決める
- Vが「実際に取り出す特徴」を運ぶ
12.7 最も混同しやすい点:隠れ状態は埋め込みテーブルではない
12.7.1 埋め込みテーブルとは?
埋め込みテーブルEはモデルのパラメータです。Token IDを受け取り、最初のベクトルを取り出します。
同じToken IDなら、表から同じ基礎ベクトルを取得します。位置情報が加わり、複数のTransformer Blockを通るにつれて、現在の文脈に応じた表現へ変わっていきます。
12.7.2 隠れ状態とは?
X_0、X_1、X_2……は、今回の順伝播で作られる中間結果です。一般に隠れ状態、または活性値と呼びます。
モデルが現在の系列を処理しながら書く「一時的な作業メモ」だと考えてください。系列が変われば、同じTokenでも後ろの層での隠れ状態は変わり得ます。
12.7.3 Attentionは入力を直接書き換えるのか?
いいえ。
Attention分岐はXから新しいテンソルH_attnを計算します。次章で説明するように、一般的な残差接続では、その分岐出力を主経路へ足します。
こうして新しい隠れ状態ができます。Attentionが元のXをその場で書き換えるわけでも、この順伝播中に埋め込みテーブルEを書き換えるわけでもありません。
したがって、PVを「元のTokenの初期値を少し正確にする操作」と説明するのは正確ではありません。より正確には:
PVは、現在の系列、現在の層、現在のヘッドに対応する、一時的で文脈依存の表現を作ります。
12.8 学習中、パラメータはいつ変わるのか?
一回の学習を三段階に分ければ、混同しなくなります。
12.8.1 第1段階:順伝播
モデルは埋め込みテーブルEと、W_Q、W_K、W_V、W_Oなどの重みを読み、隠れ状態、予測、損失を計算します。
この段階で多くの活性値が作られますが、パラメータの値はまだ変わっていません。
12.8.2 第2段階:逆伝播
損失から出発して、学習可能な各パラメータの勾配を計算します。
勾配は、「どちらへ、どれくらい動かすべきか」を表します。勾配を計算しただけでは、まだパラメータ更新そのものではありません。
12.8.3 第3段階:オプティマイザによる更新
最後にオプティマイザが勾配を使ってパラメータを変えます。最も単純な勾配降下法の記法なら:
この段階が終わって初めて、埋め込みテーブルと各層の重みが新しい値になります。次のバッチは更新後のパラメータを読みます。
推論では通常、順伝播だけを行い、backwardもoptimizer stepもありません。したがって、通常の文章生成が会話しながらモデルパラメータを書き換えることはありません。KV Cacheは途中のKとVを保存しますが、それも現在の推論のためのキャッシュであり、学習パラメータではありません。
12.9 少し珍しい例:つげ義春
学習コーパスに、漫画家の名前「つげ義春」が何度も登場するとします。どの入門書にも出てくる例ではありませんが、固有名詞が小さな専門領域の文章に繰り返し現れる例として考えてください。
モデルが最初にこの名前へ出会ったとき:
- 入力中の各Tokenが埋め込みテーブルから基礎ベクトルを取得する
- Attentionと後続のネットワークが、文全体に応じた隠れ状態を作る
- 予測と正解から損失を計算する
- 逆伝播で勾配を計算する
- オプティマイザが関連する埋め込みや他の重みを少し更新する
次に「つげ義春」が現れたとき、モデルは前回のオプティマイザ更新後のパラメータを使います。ただし、それは前回のAttention出力を埋め込みテーブルへ直接書き戻したからではありません。学習が次の流れを最後まで通ったからです。
順伝播 → 損失 → 逆伝播 → オプティマイザ更新
多くの学習を経ると、基礎埋め込みはコーパス全体で再利用できる情報を学びます。一方、各出現位置の隠れ状態は、周囲のTokenに応じて引き続き変わります。
二つの層を同時に覚えてください。
- 埋め込みパラメータ:長い学習で得られ、モデルに保存される基礎表現
- 隠れ状態:現在の入力に対して一時的に計算される文脈依存の表現
12.10 どれがパラメータなのか?
| 名前 | 学習可能なパラメータ? | いつ存在し、いつ変わるか |
|---|---|---|
| 埋め込みテーブルE | はい | オプティマイザ更新後に変わる |
| W_Q、W_K、W_V、W_O | はい | オプティマイザ更新後に変わる |
| Q、K、V | いいえ | 順伝播のたびに再計算 |
| Attentionの重みP | いいえ | 順伝播のたびに再計算 |
| Attention出力 | いいえ | 順伝播のたびに再計算 |
| 隠れ状態X_l | いいえ | 順伝播のたびに再計算 |
| KV Cache | いいえ | 推論中に保存、追加 |
この表が、本章で最も大切な境界です。
12.11 すべてのヘッドが同じW_Qを共有するのか?
この疑問は、もう少し丁寧に言い換えたほうが正確です。
一般的な実装では、一つの大きな線形層でQ全体を一度に計算し、そのあと複数のヘッドへreshapeします。その大きな行列の中には、各ヘッドに対応する異なる列の部分があります。
したがって:
- 保存と計算の形では、一つの大きなW_Qから各ヘッドを作れる
- 学習される値としては、各ヘッドが別の部分を使い、全ヘッドが同じ数字を繰り返し使うわけではない
W_KとW_Vも同じです。
異なるTransformer Blockは通常、それぞれ独立したAttentionパラメータを持ちます。層をまたいでパラメータを共有する特殊な構成もありますが、ここで説明している標準的な場合とは別です。
12.12 Attentionのパラメータ数
一般的な等幅のMulti-Head Attentionで、biasを無視すると:
d_model = 512なら:
1層のAttention重み = 4 × 512 × 512 = 1,048,576
12層なら:
12 × 1,048,576 = 12,582,912
これはAttentionの射影重みだけの数です。bias、埋め込み、FFN、LayerNorm、出力層は含みません。
学習の反復回数を増やしても、パラメータ数は増えません。学習が変えるのは既存パラメータの値であって、構造の中にあるパラメータの個数ではありません。モデルの規模は主に、語彙サイズ、層数、幅、FFNの次元、そしてアーキテクチャで決まります。
12.13 因果関係を一本につなぐ
Multi-Head Attentionの最後までを、最初から順に並べます。
現在の隠れ状態X ↓ 線形射影でQ、K、Vを作る ↓ QKᵀ → スケーリング → Mask → Softmax ↓ 重みPとVを掛ける ↓ 各ヘッドの出力をConcatenate ↓ W_Oを適用 ↓ Attention分岐の出力を得る
通常の順伝播では、この流れは活性値を作るだけです。
学習時には、さらに続きます。
予測 → 損失 → 逆伝播 → オプティマイザ更新
ここまで来て初めて、埋め込みテーブルとW_Q、W_K、W_V、W_Oが実際に変わります。
この章のチェックリスト
- QKᵀは適合度スコアを作り、スケーリング、Mask、Softmaxを経てAttentionの重みになる
- Pが混ぜ方を決め、Vが混ぜる特徴を運ぶ
- Concatenateが一つのToken表現へ戻し、W_Oがヘッド出力の再構成を学ぶ
- Attentionの順伝播は新しい隠れ状態を作り、埋め込みテーブルを直接書き換えない
- 逆伝播は勾配を計算し、オプティマイザがパラメータを更新する
- Q、K、V、Attentionの重み、KV Cacheは実行時の値であり、モデルパラメータではない
- 一つの大きな射影行列は、各ヘッド向けの異なるパラメータ部分を持てる
Part 3のまとめ
ここまでで、Attentionの幾何学的な直感、QKV、ヘッドの分割、結合、出力射影を一本につなぎました。
次の式を見たとき:
計算方法だけでなく、どれが現在の入力から生まれる活性値で、どれが一時的な混合重みなのか、そして学習時にパラメータがいつ変わるのかまで説明できるはずです。
それが、QKV出力の本質です。
次章予告
次章は残差接続とDropoutです。
- 残差接続はネットワークの主経路に直接通れる道を残し、深いモデルを最適化しやすくする
- Dropoutは学習時に活性値の一部をランダムに落とし、正則化する
また、LayerNormを残差分岐の前に置くか後ろに置くかで、Pre-NormとPost-Normの違いも生まれます。次章で続けて見ていきましょう。
今日はここまでです。次章でまた会いましょう。