すべての出発点:線形変換
深層学習の世界には、最も基本的で、最も頻繁に現れる演算がある。線形変換 である。突き詰めれば、行列積によって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 に対して Wq、Wk、Wv の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 行列、Wq、Wk、Wv、FFN の W1 と W2、最終出力層の 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 を見れば、どれもこの基礎枠組みに局所的な最適化を加えたものであり、核心の論理は変わっていないと分かる。