すべての出発点:線形変換

深層学習の世界には、最も基本的で、最も頻繁に現れる演算がある。線形変換 である。突き詰めれば、行列積によって1つのベクトルを別のベクトルへ変えるだけだ。

y = Wx

x は入力ベクトル、W は行列で、その中の数値はモデルが学習したパラメータ、y は出力ベクトルである。これだけのことだ。しかし、この単純な演算の背後には非常に豊かな幾何学的意味があり、深層学習全体の土台となっている。

なぜ「線形」と呼ぶのか

「線形」には厳密な数学的定義があり、2つの条件を満たす。

加法性: 2つの入力を別々に変換してから足した結果と、先に入力を足してから変換した結果が同じである。すなわち f(a + b) = f(a) + f(b)

斉次性: 入力を先に k 倍してから変換した結果と、先に変換してから k 倍した結果が同じである。すなわち f(k × a) = k × f(a)

この2条件を合わせると、線形変換は ベクトル空間の基本構造を保つ ことを意味する。空間を「ゆがめる」のではなく、回転、拡大縮小、射影、せん断といった一様な操作だけを行う。直線は変換後も直線であり、平行線は変換後も平行で、原点は決して動かない。

これに対し、f(x) = x² のような操作は非線形である。f(2+3) = 25 だが、f(2) + f(3) = 4 + 9 = 13 で、両者は等しくない。

2D の具体的な数値で感覚をつかむ

2次元ベクトル x = [1, 0] と、2×2 行列 W があるとする。

W = | 2  0 |
    | 0  3 |

y = Wx = | 2×1 + 0×0 | = | 2 |
         | 0×1 + 3×0 |   | 0 |

この W は x 方向を2倍、y 方向を3倍にする。これは 拡大縮小変換 である。

別の行列も見てみよう。

W = | 0  -1 |
    | 1   0 |

x = [1, 0] の場合:y = | 0×1 + (-1)×0 | = |  0 |
                        | 1×1 +   0×0 |   |  1 |

x = [0, 1] の場合:y = | 0×0 + (-1)×1 | = | -1 |
                        | 1×0 +   0×1 |   |  0 |

[1, 0][0, 1] へ、[0, 1][-1, 0] へ変わった。これは 反時計回りに90度回転 する変換である。重要なのは、W 行列の数値が空間をどう変換するかを決める一方、計算手順は常に同じ機械的な行列積だということだ。

次元を変えられる——極めて重要な性質

ここまでの例は2D から2D への変換だったが、線形変換はベクトルの次元を変えることもできる。m×n 行列は、n 次元ベクトルを m 次元ベクトルへ変換できる。

W の形状:(3, 2)    x の形状:(2,)    y = Wx の形状:(3,)

W = | 1  0 |
    | 0  1 |       x = | 1 |      y = | 1 |
    | 1  1 |           | 2 |          | 2 |
                                      | 3 |

2次元ベクトルが3次元空間へ「持ち上げられた」。逆に、(2, 3) 行列なら3次元ベクトルを2次元空間へ「圧縮」できる。この次元変換能力は深層学習のあらゆる場所で使われる。nn.Linear(in_features, out_features) は本質的に、形状 (out_features, in_features) の行列積にバイアスベクトルを加えたものである。


「射影」を理解する:影から始める

Transformer の論文やチュートリアルには「射影(projection)」という言葉が頻繁に出てくる。具体的には何を意味するのか。

最も直感的な理解:影

真上から日光が差す中、箸を1本持ち上げる場面を想像しよう。地面には影ができる。箸は3次元空間にある物体、すなわち3D ベクトルであり、地面の影は2次元平面への 射影 である。

重要な観察は、影が箸の水平方向の情報を残す一方、垂直方向の情報を 失う ことだ。影の長さから箸がどれほど高い位置にあるかは分からず、水平方向にどれほど長いかだけが分かる。

これが射影の本質である。高次元の情報を低次元空間へ圧縮し、その過程で一部の側面を選択的に残しながら、別の側面を避けられず捨てる。

数値で確認する

3D ベクトル v = [3, 4, 5] を xy 平面、つまり「地面」へ射影するとする。これは z 成分をそのまま捨てることに相当する。

射影行列 W = | 1  0  0 |
              | 0  1  0 |

射影結果 = W × v = | 1×3 + 0×4 + 0×5 | = | 3 |
                   | 0×3 + 1×4 + 0×5 |   | 4 |

3D ベクトル [3, 4, 5] は2D ベクトル [3, 4] になり、z 方向の情報である5は完全に捨てられた。

しかし、これは最も単純な射影にすぎない。より興味深いのは、射影方向が座標軸に沿っていない場合 である。

「どの壁へ映すか」で見えるものが変わる

部屋の中で箸を持っているとしよう。真上から光が差せば、影は床へ落ちる。床への射影だ。しかし左から光が差せば、影は右の壁へ落ちる。別の平面への射影である。2つの影が残す情報も、失う情報も異なる。

数学的には、どの部分空間へ射影するかは射影行列 W によって完全に決まる。異なる W は角度の異なる光源のように、同じベクトルの別の「側面」を照らし出す。

理解を深めるための比喩

1人の人間が目の前に立っているとする。その人は、身長、体重、髪型、表情、服装、声など無数の次元を持つ「高次元の対象」である。

  • 正面から撮影する——1つの射影であり、表情と服装は見えるが、後頭部の髪型は見えない。
  • 横から撮影する——別の射影であり、横顔と身長の比率は分かるが、正面の表情は見えない。
  • 写真を撮らず録音だけする——さらに別の射影であり、声の次元だけを残し、視覚情報をすべて捨てる。

どの射影も、同じ高次元の対象に対する簡略化された視点である。情報を失う代わりに、ある特定の側面をより明確で集中的に表現できる。これが深層学習で射影が重要な理由だ。高次元空間の情報は豊富すぎるため、タスクごとに異なる射影行列を使い、現在必要な側面を取り出す必要がある。

Transformer の Q、K、V とどう関係するか

次の式を考える。

Q = X × Wq
K = X × Wk
V = X × Wv

同じ token embedding X を、3つの異なる行列で3つの異なる部分空間へ射影している。角度の異なる3面の壁に、同じ箸が異なる形の影を落とすのと同じだ。各壁が箸の異なる側面を捉える。

  • Wq による影は「自分が何を探しているか」を強調する
  • Wk による影は「どのような query と一致できるか」を強調する
  • Wv による影は「自分が持つ実際の内容」を強調する

注意: 厳密な数学で「射影」と呼ぶには、2回射影しても1回と同じになる P² = P という条件が加わる。しかし、深層学習で「射影」と言うときは通常それほど厳密ではなく、情報の特定側面を抽出するため、ある空間から別の空間へデータを写すという日常的な意味に近い。


Transformer における線形変換の4つの役割

先へ進む前に、全体像を整理しよう。Transformer では、線形変換が4つの異なる役割を担う。

役割1:Embedding 層。 離散的な token ID を連続ベクトルへ写す。本質的には大きなルックアップテーブルだが、one-hot ベクトルと embedding 行列の積、すなわち線形変換としても理解できる。

役割2:Q/K/V 射影。 汎用的な token 表現を、Attention が必要とする異なる意味部分空間へ射影する。

役割3:Feed-Forward Network。 2つの線形変換の間に非線形活性化を挟み、各位置で複雑な特徴変換を行う。

役割4:最終出力層。 最終層の hidden state を語彙数と同じ次元へ射影する。各次元が token のスコアに対応し、softmax で確率分布へ変える。

線形変換だけでは不十分な理由——非線形活性化の必要性

ニューラルネットワークが線形変換だけで構成されると、致命的な問題がある。複数の線形変換を重ねても、結果は線形変換のままである。

y = W2 × (W1 × x) = (W2 × W1) × x = W_combined × x

2層ネットワークと1層ネットワークは数学的に等価である。100層重ねても意味はなく、最後には1つの行列へまとめられる。そのため、線形変換の後に ReLU や GELU などの 非線形活性化関数 を加え、複雑な非線形パターンを表現できるようにする。Transformer の Feed-Forward Network は次の構造を持つ。

FFN(x) = GELU(x × W1 + b1) × W2 + b2

最初に線形変換し、通常は4倍の高次元へ射影する。次に GELU で非線形性を導入し、もう一度線形変換して元の次元へ戻す。この「拡張・活性化・圧縮」によって、高次元空間で複雑な特徴の組み合わせと選択を行い、再び圧縮する。


手計算による実演:1つの文が Transformer を通る完全な旅

ここからは、極端に単純化しながらも完全な例を使い、入力から出力までの各段階を追う。手計算できるよう次元を非常に小さくするが、各段階の論理は実際のモデルとまったく同じである。

ミニ Transformer の設定

語彙数:6語 → {I, love, cats, hate, dogs, .}
Embedding 次元:4(実際のモデルは 768~4096)
Attention Head は1つだけ(実際のモデルは 8~128)
Q/K/V 次元:4(簡略化のため次元を削減しない)

入力文:“I love cats”

第1段階:Tokenization——文字を数値へ変える

モデルは文字を認識せず、数値だけを扱う。Tokenizer が各単語を語彙内の ID へ写す。

"I"    → token ID: 0
"love" → token ID: 1
"cats" → token ID: 2

入力シーケンス:[0, 1, 2]

実際のモデルでは BPE などの subword 分割により、さらに複雑になるが、本質は同じである。文字列を整数列へ変える。

第2段階:Token Embedding——ID からベクトルを引く

モデルは形状 (vocab_size, d_model) = (6, 4) の Embedding 行列を持つ。各行が1語のベクトル表現に対応する。これらの数値は人間が手で決めたものではなく、学習されたもの である。

Embedding 行列 E (6×4):
         dim0   dim1   dim2   dim3
ID 0 (I):     [ 1.0,   0.2,  -0.5,   0.3]
ID 1 (love):  [ 0.1,   0.9,   0.8,  -0.2]
ID 2 (cats):  [ 0.6,  -0.1,   0.4,   0.7]
ID 3 (hate):  [-0.1,   0.8,  -0.7,   0.2]
ID 4 (dogs):  [ 0.5,  -0.3,   0.3,   0.8]
ID 5 (.):     [ 0.0,   0.0,   0.1,   0.0]

Token ID で行を参照する。

"I"    → [1.0,  0.2, -0.5,  0.3]
"love" → [0.1,  0.9,  0.8, -0.2]
"cats" → [0.6, -0.1,  0.4,  0.7]

各単語は無味乾燥な ID ではなくなり、単語の意味情報を含む4次元空間上の点になった。

第3段階:Positional Encoding を加える——位置情報を注入する

なぜ必要なのか。Attention は permutation invariant、すなわち置換不変 だからだ。Q·K の内積は、2つのベクトルの方向関係だけを見て、シーケンス内の位置をまったく考慮しない。位置情報がなければ、“I love cats” と “cats love I” はモデルにとって同じものになる。

位置 0 の encoding:[0.00,  0.01,  0.00,  0.01]
位置 1 の encoding:[0.84,  0.05,  0.04,  0.05]
位置 2 の encoding:[0.91, -0.04,  0.08,  0.03]

Token embedding へ直接加える。

X0 ("I",    pos=0) = [1.00, 0.21, -0.50, 0.31]
X1 ("love", pos=1) = [0.94, 0.95,  0.84, -0.15]
X2 ("cats", pos=2) = [1.51, -0.14, 0.48,  0.73]

同じ単語でも、現れる位置によってベクトルが変わる。これが位置認識である。

第4段階:線形射影で Q、K、V を生成する

先ほどの「角度の異なる3面の壁」に当たる。3つの重み行列はいずれも (4, 4) で、学習によって得られる。

Wq = | 0.5  0.0  0.1  0.0 |     Wk = | 0.3  0.1  0.0  0.2 |     Wv = | 0.1  0.0  0.5  0.0 |
     | 0.0  0.6  0.0  0.1 |          | 0.0  0.4  0.1  0.0 |          | 0.0  0.3  0.0  0.2 |
     | 0.1  0.0  0.4  0.0 |          | 0.1  0.0  0.5  0.1 |          | 0.2  0.0  0.4  0.1 |
     | 0.0  0.1  0.0  0.5 |          | 0.0  0.1  0.0  0.3 |          | 0.0  0.1  0.0  0.6 |

“I” の X0 から Query を手計算してみる。

Q0 = X0 × Wq = [1.00, 0.21, -0.50, 0.31] × Wq

Q0[0] = 1.00×0.5 + 0.21×0.0 + (-0.50)×0.1 + 0.31×0.0 = 0.45
Q0[1] = 1.00×0.0 + 0.21×0.6 + (-0.50)×0.0 + 0.31×0.1 = 0.157
Q0[2] = 1.00×0.1 + 0.21×0.0 + (-0.50)×0.4 + 0.31×0.0 = -0.10
Q0[3] = 1.00×0.0 + 0.21×0.1 + (-0.50)×0.0 + 0.31×0.5 = 0.176

Q0 ≈ [0.45, 0.16, -0.10, 0.18]

同じ計算を各 token に対して WqWkWv の3回行い、次を得る。

        Q(「何を探すか」)          K(「何と一致できるか」)      V(「実際の内容」)
"I"   : [0.45, 0.16,-0.10, 0.18]  [0.36, 0.12,-0.20, 0.13]  [0.05, 0.12,-0.09, 0.21]
"love" : [0.55, 0.56, 0.43,-0.01]  [0.37, 0.46, 0.51, 0.05]  [0.51, 0.25, 0.53,-0.02]
"cats" : [0.81,-0.02, 0.34, 0.35]  [0.60, 0.02, 0.39, 0.25]  [0.39, 0.11, 0.49, 0.42]

同じ token の Q、K、V は3つの異なるベクトルである。同じ箸が3面の壁へ落とす異なる影だ。

第5段階:Attention Scores を計算する——Q と K の内積

各 token の Q と、すべての token の K の内積を取り、「誰に注目すべきか」を測る。“love” の視点、すなわち Q1 を例にする。

score(love→I)    = Q1 · K0 = 0.55×0.36 + 0.56×0.12 + 0.43×(-0.20) + (-0.01)×0.13
                           = 0.198 + 0.067 - 0.086 - 0.001 = 0.178

score(love→love) = Q1 · K1 = 0.55×0.37 + 0.56×0.46 + 0.43×0.51 + (-0.01)×0.05
                           = 0.204 + 0.258 + 0.219 - 0.001 = 0.680

score(love→cats) = Q1 · K2 = 0.55×0.60 + 0.56×0.02 + 0.43×0.39 + (-0.01)×0.25
                           = 0.330 + 0.011 + 0.168 - 0.003 = 0.506

√d_k = √4 = 2 で割ってスケーリングし、内積が大きくなりすぎて softmax が勾配飽和領域へ入ることを防ぐ。

scaled scores = [0.178/2, 0.680/2, 0.506/2] = [0.089, 0.340, 0.253]

第6段階:Softmax——確率分布へ変える

exp(0.089) = 1.093
exp(0.340) = 1.405
exp(0.253) = 1.288

合計 = 1.093 + 1.405 + 1.288 = 3.786

attention_weights = [1.093/3.786, 1.405/3.786, 1.288/3.786]
                  = [0.289,       0.371,        0.340]

これは、“love” が新しい表現を生成するとき、“I” へ28.9%、自分自身へ37.1%、“cats” へ34.0%の注意を割り当てることを示す。“love” は自分自身と “cats” へ最も注目している。動詞と目的語には自然に強い関係がある。

第7段階:V の加重和——情報を取り出す

Attention weights を使い、すべての token の Value ベクトルを加重平均する。

output_love = 0.289 × V_I  +  0.371 × V_love  +  0.340 × V_cats

= 0.289 × [0.05, 0.12, -0.09, 0.21]
+ 0.371 × [0.51, 0.25,  0.53,-0.02]
+ 0.340 × [0.39, 0.11,  0.49, 0.42]

dim0: 0.289×0.05 + 0.371×0.51 + 0.340×0.39 = 0.014 + 0.189 + 0.133 = 0.336
dim1: 0.289×0.12 + 0.371×0.25 + 0.340×0.11 = 0.035 + 0.093 + 0.037 = 0.165
dim2: 0.289×(-0.09)+0.371×0.53+ 0.340×0.49 =-0.026 + 0.197 + 0.167 = 0.338
dim3: 0.289×0.21 + 0.371×(-0.02)+0.340×0.42= 0.061 - 0.007 + 0.143 = 0.197

output_love ≈ [0.336, 0.165, 0.338, 0.197]

この新しいベクトルは “love” だけを表すものではない。Attention weights に従って “I” と “cats” の成分を混ぜ、文全体のコンテキスト情報を融合している。これが Attention の出力、すなわちコンテキストを認識した表現である。

第8段階:Feed-Forward Network——深い特徴変換

Attention の出力は2層の feed-forward network を通る。

まず拡張:    4次元 → 16次元(W1 を掛ける)
非線形化:    GELU 活性化
再び圧縮:   16次元 → 4次元(W2 を掛ける)

拡張によって高次元空間で複雑な特徴を組み合わせ、GELU が非線形性を導入して複雑なパターンを学べるようにし、圧縮で情報を元の次元へ戻す。各段階の間には residual connection、すなわち入力を出力へ加える処理と LayerNorm もある。

実際のモデルでは、以上の Attention + FFN が多数積み重なる。GPT-3 は96層、LLaMA は32~80層を持つ。各層が前の層の出力へ Attention と FFN を適用し、次第に抽象度の高い意味表現を構築する。


Hidden State:モデル内部の中間生成物

多層を通過したところで、重要な概念である hidden state を理解する必要がある。

“I love cats” の3つの token は、embedding + positional encoding の後、それぞれ4次元ベクトルを持つ。この3つのベクトルが 第0層の hidden states である。

次に、第1層の Attention + FFN へ入る。コンテキストの融合と特徴変換によって各 token のベクトルが変わる。新しい3つのベクトルが 第1層の hidden states である。さらに第2層へ入ると、再び変わる。

入力 embedding:                [1.00, 0.21, -0.50, 0.31]  ← “I” の初期表現
                                      │
第1層 Attention+FFN の後:      [0.72, 0.35, -0.12, 0.48]  ← hidden state (layer 1)
                                      │
第2層 Attention+FFN の後:      [0.55, 0.61,  0.20, 0.33]  ← hidden state (layer 2)
                                      │
第3層 Attention+FFN の後:      [0.82,-0.15,  0.63, 0.91]  ← hidden state (layer 3, 最終層)

各層の hidden state は常に4次元で、次元数は変わらない。しかし、内部の数値は各層で更新される

なぜ “hidden” と呼ぶのか

これらの中間ベクトルは外部から見えないためである。ユーザーに見えるのは最終的に出力される token、たとえば “.” だけだ。モデル内部の第1層や第2層で各 token のベクトルがどのような値かは見えず、モデルの中に「隠れて」いる。

見えるもの:      入力 “I love cats” → 出力 “.”
見えないもの:    各層における各 token の中間ベクトル ← これが hidden states

この用語は Transformer が発明したものではなく、RNN の時代から存在した。RNN も各時刻で内部ベクトルを生成し、次の時刻へ渡す。そのベクトルも hidden state と呼ばれる。Transformer はこの用語を引き継いだ。

最終層の hidden state が特別な理由

GPT 系の自己回帰モデルでは、各位置で「次の token は何か」を予測する。最後の token “cats” の hidden state はすべての層を通り、“I love cats” という文全体の情報を十分に吸収しているため、次の単語の予測に使われる。

位置 0 (“I”) の最終 hidden state     → “I” の次を予測     → “love”
位置 1 (“love”) の最終 hidden state  → “love” の次を予測  → “cats”
位置 2 (“cats”) の最終 hidden state  → “cats” の次を予測  → “.”

第9段階:最終出力層——ベクトルを単語へ戻す

すべての層を通った後、“cats” の位置にある最終 hidden state が次の値だとする。

hidden_state = [0.82, -0.15, 0.63, 0.91]

(4, 6) 行列で語彙数、すなわち6次元へ射影する。各次元が1語のスコアに対応する。

logits = hidden_state × W_output

次が得られたとする:
logits = [0.1, 0.3, 0.1, -0.8, 0.5, 1.2]
          "I"  "love" "cats" "hate" "dogs"  "."

Softmax で確率へ変換する。

probabilities ≈ [0.08, 0.10, 0.08, 0.03, 0.12, 0.59]
                  "I"  "love" "cats" "hate" "dogs"  "."

次の token は “.” である確率が最も高く、59%と予測された。“I love cats” の後にピリオドが続くのは自然である。


すべての行列は学習によって得られる

全工程に登場した すべての行列、すなわち Embedding 行列、WqWkWv、FFN の W1W2、最終出力層の W_output は、すべて学習によって得られる。行列内の数値が モデルパラメータ(parameters) である。「GPT-3 は1,750億パラメータを持つ」とは、これらすべての行列に含まれる数値の総数を指す。

学習開始時、すべての行列はランダムに初期化され、モデルの出力はほぼ意味をなさない。学習過程が本質的に行うことは、次の循環である。

1. “I love cats” のようなテキストをモデルへ与える
2. 現在のパラメータで次の token を予測し、たとえば “dogs” の確率が最も高くなる
3. 正解は “.” なので、モデルの予測は誤り
4. どれほど誤ったか、すなわち loss を計算する
5. Backpropagation で各パラメータをどの方向へどれだけ変えるべきか計算する
6. すべての行列の数値を少し調整する
7. 第1段階へ戻り、別のテキストで数十億回繰り返す

膨大なデータで調整を繰り返すと、行列の数値はランダム値から意味ある値へ少しずつ変わる。最終出力層の W_output は、どのような hidden state をどの単語へ写すべきかを学び、Wq は query 情報の抽出方法を学び、Embedding 行列は意味の近い単語が近いベクトルを持つよう学ぶ。

興味深い点として、多くのモデルでは最終出力層の W_output と最初の Embedding 行列 E が、実際には 同じ行列の転置 である。この技術を weight tying と呼ぶ。直感的にも納得できる。Embedding は token ID をベクトルへ写し、出力層はベクトルを token ID へ戻す。両者は逆方向の過程であり、パラメータ共有によってメモリを節約しつつ、両端の意味空間を一致させられる。


全工程の一覧

"I love cats"
     │
     ▼
① Tokenization:      [0, 1, 2]                    文字 → 数値
     │
     ▼
② Token Embedding:    3つの4次元ベクトル             数値 → ベクトル(参照)
     │
     ▼
③ + Positional Enc:   位置情報を注入                  ベクトル + 位置
     │
     ▼
④ Linear → Q, K, V:   3組の射影                      3つの異なる視点
     │
     ▼
⑤ Q · Kᵀ:            Attention score を計算          誰が誰へ注目するか
     │
     ▼
⑥ Softmax:            確率分布へ変換                  どれほど注目するか
     │
     ▼
⑦ V の加重和:         コンテキストを融合              新しい表現を生成
     │
     ▼
⑧ FFN:                深い特徴変換                    ×N 層を積み重ねる
     │
     ▼
⑨ Output Projection:  4次元 → 6次元(語彙)           ベクトル → 確率
     │
     ▼
次の token: "."  (確率が最大)

おわりに

Transformer を理解するために、最初からすべての数式展開を理解する必要はない。重要なのは、いくつかの核心的な直感をつかむことである。

線形変換は基礎演算である。 行列積によって、ある空間から別の空間へベクトルを写し、モデル全体の最も基本的な構成要素になる。

射影は情報を選択的に抽出する。 異なる射影行列が、異なる角度から撮影するように、同じ入力から異なる側面の情報を取り出す。

Attention により、各 token は他のすべての token を直接参照できる。 Q·K の一致で関連 token を見つけ、V からその情報を取り出し、グローバルなコンテキストを融合した新しい表現を作る。

非線形活性化は、ネットワークを線形性の限界から解放する。 これがなければ、どれほど深いネットワークも1層と等価になる。

すべてのパラメータは学習される。 膨大なデータで試行錯誤を繰り返し、各行列がどのような値を持つべきかを徐々に学ぶ。

これらを理解してから論文のさらに複雑な変種、Multi-Head Attention、RoPE、FlashAttention、Group Query Attention を見れば、どれもこの基礎枠組みに局所的な最適化を加えたものであり、核心の論理は変わっていないと分かる。