Skip to content

第9章 Transformerの全体像

第8章で、私たちはTransformerの中核であるattentionを完全に分解しました。この章では、その中核の周りに必要な部品を一つずつ取り付けて、Transformerという一つの機械を完成させます。

部品は4つです。位置エンコーディング(語順を教える)、残差接続(深く積んでも学習できるようにする)、層正規化(値の暴れを抑える)、FFN(集めた情報を各トークンの中で加工する)。どれも、attentionを支えるために「なければ困る理由」がはっきりある部品です。この章では毎回その「困る理由」から入ります。

そして最後に、完成したTransformerが「猫は魚が好き」を "Cats like fish" に翻訳する様子を、入口から出口まで通しで追いかけます。

この章で学ぶこと

  • 原論文 "Attention Is All You Need"(2017)と、Transformerが生まれた経緯
  • 全体アーキテクチャ(エンコーダ・デコーダ)の見取り図
  • 位置エンコーディング: attentionは語順を知らない、という事実とその対策
  • 残差接続: 深いネットワークでも勾配が消えない「高速道路」
  • 層正規化(LayerNorm): 値のスケールを整えて学習を安定させる
  • FFN: attentionが「混ぜる係」、FFNが「考える係」という役割分担
  • エンコーダブロック/デコーダブロックの組み立てと、 N 回積み重ねる構造
  • cross-attention: 第7章のseq2seq attentionの正体
  • 出力層: 語彙全体の確率分布を出すまで
  • 翻訳例「猫は魚が好き」→ "Cats like fish" の一部始終
  • パラメータはどこに何個あるのか(一覧表と概算)

この章の前提


9.1 原論文 "Attention Is All You Need"

2017年、Google の研究者たち(Vaswani ら8名)が発表した論文 "Attention Is All You Need"(注意こそすべて) で、Transformerは世に出ました。もともとは機械翻訳のためのモデルです。当時の翻訳の主流は「RNNベースのseq2seq + attention」(第7章)でしたが、この論文は「RNNを完全に捨てて、attentionだけでseq2seqを作ってみたらどうか」という挑発的な提案をしました。

動機は第7章と第8章で見たとおりです。RNNは逐次処理のせいで並列化できず、訓練が遅い。一方attentionは、全トークンを行列積で同時に処理でき、どんなに離れた単語も直接つなげる。だったらRNNの部分は要らないのではないか、というわけです。結果は、翻訳の品質で当時の最高記録を更新し、しかも訓練時間は大幅に短縮されました。この「質を落とさず並列化できる」性質こそが、後にモデルの巨大化(第13章)を可能にし、LLM時代の扉を開くことになります。

原論文のTransformerは、第7章のseq2seqと同じくエンコーダ・デコーダ構成です。

  • エンコーダ(encoder): 入力文(例:「猫は魚が好き」)を読み込み、各トークンの「文脈化されたベクトル」(第8章で学んだ、まわりの単語の情報を取り込んで「その文の中での意味」を反映したベクトル)の列を作る(読解係)
  • デコーダ(decoder): エンコーダの結果を参照しながら、出力文("Cats like fish")を1トークンずつ生成する(作文係)

ただし第7章のseq2seqと違い、文全体を1本の固定長ベクトルに押し込むボトルネックはありません。エンコーダの出力は「トークン数ぶんのベクトルの列」のまま保たれ、デコーダは毎ステップ、その全部をattentionで見に行きます。

9.2 全体像を眺める — 本書最重要図

まず完成形の見取り図を示します。この図は本書で最も重要な図の一つです。 現時点で細部が分からなくて大丈夫です。この章の各節がこの図の部品を1つずつ説明し、章の終わりに戻ってきたとき、全部が読めるようになっています。

読み方のポイントは3つです。

  1. 左右2本の塔がある。左がエンコーダ(読解係)、右がデコーダ(作文係)
  2. 各塔は、同じ構造のブロックを N積み重ねてできている(原論文では N=6)
  3. 2本の塔をつなぐ橋が cross-attention。デコーダはここを通じて入力文を参照する

それでは部品を1つずつ見ていきます。最初は、第8章の最後に予告した「attentionは語順を知らない」問題からです。


9.3 位置エンコーディング — attentionは語順を知らない

9.3.1 まず事実を確認する: 語順を入れ替えても結果が同じ

まず、意外に思うかもしれない事実から始めます。第8章のattentionは、トークンの順番を完全に無視します。

第8章の手計算を思い出してください。トークン i の出力を決めるのは、①自分のクエリ qi 、②全トークンのキーとバリュー、の2つだけでした。この計算のどこにも「トークン j は何番目にあるか」という情報は登場しません。スコアはクエリとキーの内積だけで決まり、内積は相手が隣にいようが100トークン先にいようが同じ値です。

具体的に確かめましょう。第8章の例で、 X の行の順番を [猫, 魚, それ] から [魚, 猫, それ] に入れ替えたとします。すると:

  • Q,K,V の行も同じように入れ替わるだけ(各行の中身は変わらない)
  • スコア表 QK は、行と列が同じように入れ替わるだけ(「それ」と「魚」の内積4は、位置がどこでも4)
  • softmaxは行ごとの計算なので、重みも入れ替わるだけ
  • 結局、「それ」の出力ベクトルは (0.159, 1.841) のまま、1ミリも変わりません

つまりattentionにとって、文は「単語の」ではなく「単語の」です。袋に [猫, は, 魚, が, 好き] を放り込んでも [魚, は, 猫, が, 好き] を放り込んでも、各単語が受け取る情報は同じ。しかし「猫は魚が好き」と「魚は猫が好き」は意味が違います。「猫が魚を食べた」と「魚が猫を食べた」なら大事件です。語順は言葉の意味の一部なのです。

RNN(第7章)にはこの問題がありませんでした。1トークンずつ順番に読むという構造自体が語順を織り込んでいたからです。RNNを捨てて並列処理を手に入れた代償として、語順の情報を失った。だから、語順を明示的に教え直す必要があります。

9.3.2 対策: 位置の分だけベクトルを「ずらす」

解決策は拍子抜けするほど単純です。「あなたは t 番目です」という情報をベクトルにして、埋め込みに足し算するのです。これを 位置エンコーディング(Positional Encoding) と呼びます。

xt入力=ewt+pt

読み下し: 位置 t のトークンの入力ベクトルは、「単語 wt の埋め込みベクトル」と「位置 t を表すベクトル pt 」の足し算。同じ単語でも、出てくる位置が違えば微妙に違うベクトルとしてattentionに渡る。

こうすると、同じ「魚」でも3番目の魚と7番目の魚は少し違うベクトルになるので、attentionのスコア(内積)が位置の影響を受けられるようになります。「直前の単語を見る係」(第8章のヘッド2)のような芸当も、位置情報が入っているからこそ学習できるわけです。

では、 pt はどんなベクトルにすべきでしょうか。素朴な案から検討します。

  • 案1: 位置番号そのものを足す(pt=(t,t,,t))。位置1000では1000という巨大な値が足され、埋め込みの中身(だいたい ±1 程度)が完全にかき消されてしまいます。却下
  • 案2: 0〜1に正規化する(位置 t を文長 n で割る)。同じ「3番目」でも、10単語の文と100単語の文で値が変わってしまい、「3番目」の意味が文の長さに依存してしまいます。却下

欲しい性質は、①値が暴れない(常に一定の範囲)、②どの位置も互いに区別できる、③位置同士の相対関係(2つ隣、5つ前など)が読み取りやすい、の3つです。

9.3.3 sin/cos版: 周期の違う波を束ねる

原論文の答えは、周期の異なるsin波・cos波の値を並べるというものでした。位置 t 、次元番号 2i(偶数)と 2i+1(奇数)に対して:

pt,2i=sin(t100002i/dmodel),pt,2i+1=cos(t100002i/dmodel)

読み下し: 位置ベクトルの偶数番目の成分は「位置 t を、次元ごとに違う定数で割ってからsinに入れた値」、奇数番目はcos版。次元番号 i が大きいほど分母 100002i/dmodel が大きくなる、つまり後ろの次元ほどゆっくり変化する波になる。

sin・cosの厳密な性質は本書の前提を超えるので、この式を完全に理解する必要はありません。押さえてほしいのは次のイメージだけです。sinとcosは「 1 から 1 の間を周期的に往復する波」であり、分母が大きいほど波はゆっくり(周期が長く)なります。

これは時計と同じ仕組みです。時計は「秒針(速い)・分針(中くらい)・時針(遅い)」という周期の違う3本の針の組み合わせで、一日のどの瞬間も一意に表せます。あるいは2進数の桁を思い浮かべてもかまいません。1の位は 0,1,0,1,… と毎回パタパタ変わり、上の桁ほどゆっくり変わる。桁を全部読めば、どんな数でも区別できます。位置エンコーディングは、これの「なめらか版」です。速い波が細かい位置の違いを、遅い波が大まかな位置を担当し、束ねればどの位置も一意に表せます。

dmodel=4 で実際の値を計算してみましょう。分母は、次元0・1が 100000/4=1 、次元2・3が 100002/4=100 です。なお、第6章では位置を「1番目・2番目…」と1から数えましたが、位置エンコーディングの式は t=0 始まりで書くのが慣例なので、本章では先頭を位置0とします。

位置 t次元0: sin(t)次元1: cos(t)次元2: sin(t/100)次元3: cos(t/100)
00.0001.0000.0001.000
10.8410.5400.0101.000
20.909−0.4160.0201.000
30.141−0.9900.0301.000
4−0.757−0.6540.0400.999

次元0・1(速い波、周期約6.3)は位置が1つ進むだけで大きく動き、次元2・3(遅い波、周期約628)はほとんど動きません。速い針と遅い針、そのものです。

大きく上下している系列が次元0の速い波 sin(t)(周期 約6.3)、0のすぐ上をほぼ水平に走る系列が次元2の遅い波 sin(t/100)(周期 約628)です。遅い波はこの範囲ではほとんど動きません。「大きい桁」の針に相当します。

数値例として、「猫は魚が好き」の先頭2トークンの入力ベクトルを作ってみます。埋め込みを 猫 =(1,0,1,0) 、は =(0,2,0,1) とすると:

  • 猫(位置0): (1,0,1,0)+(0, 1, 0, 1)=(1, 1, 1, 1)
  • は(位置1): (0,2,0,1)+(0.841, 0.540, 0.010, 1.000)=(0.841, 2.540, 0.010, 2.000)

読み下し: 各トークンの埋め込みに、その位置の波の値が足し込まれた。これがエンコーダ/デコーダの最初のブロックへの入力になる。

sin/cos版の利点は、学習パラメータが不要なこと、そして訓練で見た文より長い文にも(波は無限に続くので)一応対応できることです。一方、位置埋め込みを埋め込み行列と同じように学習で獲得する流儀(学習型位置埋め込み)もあり、GPT系の初期モデルはこちらを採用しました。さらに現代のLLMでは、位置の扱いをattentionの内部に組み込んだ RoPE という改良が主流になっていますが、これは第15章で扱います。ここでは「attentionは語順を知らないので、位置情報を何らかの形で注入する必要がある」という一点を持ち帰ってください。


9.4 残差接続 — 勾配の高速道路

9.4.1 困る理由: 深く積むと学習できなくなる

この章の後半で見るように、Transformerはブロックを何層も積み重ねます(原論文で6層、GPT-3級では96層)。ここで、第7章で見た勾配消失の問題が再び現れます。

第5章で学んだとおり、学習の指令(勾配)は連鎖律によって出力側から入力側へ、層を遡って伝わります。連鎖律は「変化率の掛け算」でした。1より小さい数を96回掛ければほぼ0になり、深い層(入力に近い側)には学習の指令がほとんど届きません。RNNでは「時間方向」に起きたこの問題が、深いネットワークでは「層の深さ方向」に起きるのです。

9.4.2 対策: 入力をそのまま出力に足す

解決策はまたしても足し算です。各部品(attentionやFFN)の出力に、その部品への入力をそのまま足してしまうのです。

y=x+f(x)

読み下し: 部品 f を通した結果 f(x) に、入力 x をそのまま足したものを出力とする。部品を「通り抜ける道」と並行して、「素通りする迂回路」を用意する形。これを 残差接続(residual connection) と呼ぶ。

text
      x ---------------------+
      |                      |
      v                      |     <- 迂回路(何もせず素通り)。
 +-----------+               |        勾配もここを素通りできる
 |     f     |               |     <- 部品 f (attention や FFN)
 +-----------+               |
      |                      |
      | f(x)                 |
      v                      v
      + <--------------------+     <- ここで x を足し戻す
      |
      v
   y = x + f(x)

数値例: 入力が x=(1, 0, 1, 0) で、attentionの出力が f(x)=(0.5, 0.2, 0.1, 0.3) なら、

y=(1, 0, 1, 0)+(0.5, 0.2, 0.1, 0.3)=(1.5, 0.2, 1.1, 0.3)

読み下し: 出力は「元の自分」に「attentionで集めた情報」を上乗せしたもの。

なぜこれで勾配消失が防げるのでしょうか。 y=x+f(x)x で微分すると(第3章の記法で)、

yx=1+fx

読み下し: 出力の入力に対する変化率は「1 + 部品の変化率」。部品の変化率がどんなに小さくても、必ず「1」が残る

連鎖律で層を遡るとき、各層の変化率が掛け合わされていきますが、残差接続があれば各層の係数は「 1+何か 」の形です。 0.5 を96回掛ければ消滅しますが、「 1+小さい数 」を掛け続けても1のまわりに留まれます。勾配は、部品の中を通らずとも迂回路を素通りして深い層まで届く。残差接続は「勾配の高速道路」なのです。第7章でRNNが苦しんだ勾配消失に対する、Transformer側の答えがこれです。

もう一つ、分かりやすい利点があります。残差接続があると、各部品の仕事は「入力を丸ごと作り直す」ことではなく「入力に差分(修正)を加える」ことになります(残差=引き算の残り、という名前の由来です)。「それ」のベクトルに魚の情報を上乗せする、という第8章の使い方とも自然に噛み合います。各層は少しずつベクトルを磨き上げていけばよいのです。


9.5 層正規化(LayerNorm)— 値の暴れを抑える

9.5.1 困る理由: 足し算を重ねると値のスケールが暴れる

残差接続は足し算です。埋め込み+位置エンコーディング+attentionの出力+FFNの出力+……と、層を重ねるたびに値が積み上がっていくと、ベクトルの成分がどんどん大きく(あるいは偏って)なりえます。第8章で見たとおり、softmaxは入力のスケールに敏感でした(尖りすぎ問題)。値のスケールが層ごとにバラバラだと、学習率(第4章の η)をどう選んでも、ある層では大きすぎ、別の層では小さすぎる、という事態になり、訓練が不安定になります。

9.5.2 対策: 各トークンのベクトルを「平均0・ばらつき1」に整える

そこで、要所要所で値を標準サイズに整え直します。層正規化(Layer Normalization、LayerNorm) は、各トークンのベクトル1本ごとに、成分の平均を0、ばらつき(分散)を1に揃える操作です。

ベクトル x=(x1,,xd) に対して、まず平均 μ(ミュー)と分散 σ2(シグマ2乗)を計算し、各成分を次のように変換します。分散・標準偏差は第8章8.4.2で導入した「ばらつきの大きさ」です(この σ は第5章のシグモイド関数とは別物で、標準偏差を表す統計の慣例文字です)。

yi=γixiμσ2+ϵ+βi

読み下し: 各成分から平均を引き(中心を0に)、ばらつきの平方根=標準偏差で割る(ぶれ幅を1に)。 ϵ(イプシロン)はゼロ割りを防ぐための極小の数(例: 105)。最後の γ(ガンマ)と β(ベータ)は学習されるパラメータで、「本当に平均0・ばらつき1がベストとは限らないので、最終的なスケールと位置は学習で微調整してよい」という逃げ道。

数値例: x=(2, 0, 4, 2) を正規化してみます(γ=1,β=0,ϵ0 とします)。

  • 平均: μ=(2+0+4+(2))/4=1
  • 各成分から平均を引く: (1, 1, 3, 3)
  • 分散: σ2=(12+(1)2+32+(3)2)/4=(1+1+9+9)/4=5 、標準偏差 52.236
  • 割る: (1, 1, 3, 3)/2.236(0.447, 0.447, 1.342, 1.342)

読み下し: どんなに大きな値のベクトルが来ても、LayerNormを通れば「平均0・ばらつき1」の標準サイズに整えられて出てくる。

LayerNormをどこに置くかには2つの流儀があります。原論文は「残差接続で足したに置く」Post-LNでしたが、その後「各部品に入るに置く」Pre-LNのほうが深いモデルでも訓練が安定することが分かり、GPT系を含む現代のモデルはほぼPre-LNです。本書の説明はどちらの理解にも通用するので、「ブロックの中の決まった場所で毎回値を整え直す係がいる」とだけ覚えてください。


9.6 FFN — attentionが「混ぜる係」、FFNが「考える係」

9.6.1 困る理由: attentionは混ぜることしかできない

attentionの出力は何だったでしょうか。バリューの重み付き平均です。平均は混ぜ合わせであって、新しい情報の加工ではありません。「それ」の位置に魚の情報を運んでくることはできても、「魚は食べられるものだ」「食べたのだから満腹だろう」といった知識に基づく変換・推論は、混ぜるだけの機構には荷が重いのです。第5章で学んだとおり、複雑な入出力関係を作るには非線形の変換(活性化関数を挟んだ層)が必要でした。attentionの中に、活性化関数は登場していません。

9.6.2 対策: 各トークンに小さな2層ニューラルネットを通す

そこでTransformerは、attentionの直後に フィードフォワード網(Feed-Forward Network、FFN) を置きます。正体は、第5章でさんざん練習したごく普通の2層ニューラルネットワークです。

FFN(x)=max(0, xW1+b1)W2+b2

読み下し: 入力ベクトルに1つ目の行列 W1 を掛けてバイアス b1 を足し、ReLU(マイナスを0に潰す活性化関数、第5章)を通し、2つ目の行列 W2 を掛けてバイアス b2 を足す。 W1,W2,b1,b2 はすべて学習されるパラメータ。

大事な特徴が2つあります。

特徴1: 各トークンに独立に、同じFFNが適用される。 attentionと違い、FFNはトークン同士を一切見ません。 n 個のトークンそれぞれのベクトルが、同じ W1,W2 を持つ同じFFNを、別々に通ります。役割分担はこうです。

TIP

attention = 混ぜる係(トークンで情報をやり取りする) FFN = 考える係(各トークンが、集めた情報を自分の中で加工・整理する)

会議のたとえで言えば、attentionが「全員で情報交換をする会議」、FFNが「会議後に各自が席へ戻ってやる持ち帰り作業」です。Transformerブロックは、この「会議→個人作業」のセットを何度も繰り返す組織なのです。

また、FFNは知識の貯蔵庫でもあると考えられています。「魚は食べ物」「パリはフランスの首都」のような事実知識の多くは、FFNの重みの中に蓄えられていることを示唆する研究があります。attentionが文脈から材料を集め、FFNが記憶と照合して加工する、という分業です。

特徴2: 中間層は4倍広い。 慣例として、中間の次元 dffdmodel4倍にします(原論文: dmodel=512dff=2048)。一度広い空間に展開してから畳み直すほうが、複雑な変換を表現しやすいためです。作業机は広いほうが仕事がしやすい、という感覚で捉えてください。

数値例: 小さく dmodel=2dff=4 で1トークン分を計算します。 x=(1, 1) 、バイアスは0、

W1=(10100101),W2=(10011100)

とします。

読み下し: W1 が2次元を4次元へ広げ、 W2 が4次元を2次元へ戻す(値は説明用)。

計算を追います。

  • 1層目: xW1=(1, 1, 1, 1)(2次元→4次元に展開)
  • ReLU: max(0,) でマイナスを0に潰して (1, 0, 1, 0)
  • 2層目: (1,0,1,0)W2=(1×1+1×1, 1×1)=(2, 1)(4次元→2次元に戻す)

読み下し: 広げて、非線形で刈り込んで、畳み直す。入力 (1,1)(2,1) という別のベクトルに加工された。

なお、活性化関数には第5章で名前だけ予告した GELU を使うのが現代の主流です。GELUはReLUの折れ目をなめらかにした改良版で、「マイナスをおおむね0に潰す」という役割は同じです。


9.7 エンコーダブロック — 部品を組み立てる

部品が揃いました。組み立てましょう。エンコーダブロック1個の中身は、たった2つの部品と、それぞれに付く残差接続+LayerNormです。

  1. Multi-Head self-attention(第8章。マスクなし=全トークンがお互いを見てよい)+ 残差接続 + LayerNorm
  2. FFN(9.6節)+ 残差接続 + LayerNorm

重要なのは、ブロックの入力と出力が同じ形(n×dmodel) だということです。形が変わらないから、レゴブロックのように同じ構造を何個でも積み重ねられます。原論文ではこれを N=6 個積みました。

層を重ねる意味は、第5章の「多層=関数の合成」と同じです。1層目のattentionは「それ→魚」のような表面的な関係を捉え、2層目は「1層目で文脈が混ざったベクトル同士」の関係を捉え……と、層が深くなるほど抽象的な関係を扱えるようになります。会議→個人作業→また会議→また個人作業、を6巡すれば、最初はバラバラだった各トークンのベクトルが、文全体の意味を織り込んだ深い表現に育っていくわけです。

エンコーダ塔の最終出力は、入力文の各トークンに対応する、文脈化しきったベクトルの列(n×dmodel の行列)です。第7章のseq2seqのように1本のベクトルに要約したりせず、列のまま次へ渡します。ボトルネックはありません。


9.8 デコーダブロックとcross-attention — 第7章の伏線回収

デコーダは「これまでに生成した出力文のトークン列」を受け取り、次のトークンを予測する塔です。デコーダブロックは、エンコーダブロックの2部品の間に、もう1つattentionが挟まった3部品構成です(各部品に残差接続+LayerNormが付くのは同じ)。

  1. マスク付き Multi-Head self-attention — 出力文の中でお互いを見る。ただし因果マスク付き(第8章8.10)。生成中の文の未来はまだ存在しないし、訓練時にカンニングさせないため
  2. cross-attention入力文を見に行く(後述)
  3. FFN — 考える係(エンコーダと同じ)

cross-attentionの正体

第7章で、attentionはもともと「翻訳のデコーダが、入力の全単語をもう一度見に行く仕組み」として生まれた、と学びました。あのときは「重み付き平均をとる」という発想だけ紹介し、詳細な数式は第8章に譲る、と約束しました。その正体がこれです。 cross-attention(交差注意)は、第8章の完成形の式をそのまま使い、材料の出どころだけを変えたattentionです。

CrossAttention=softmax(QdecKencdk)Venc

読み下し: クエリ Qdecデコーダ側のベクトル列から作り(Qdec=HdecWQ)、キーとバリューはエンコーダの最終出力から作る(Kenc=HencWKVenc=HencWV)。「いま英語で何と言うべきかを考えている私(クエリ)」が、「日本語の入力文の各単語(キー)」と照合し、合った単語の情報(バリュー)を持ってくる。

出力文側が m トークン、入力文側が n トークンなら、attention重みの表は m×n になります。翻訳「猫は魚が好き」→ "Cats like fish" で、訓練済みモデルに典型的な重みの例を示します(説明用の値です)。

出力側 \ 入力側好き
Cats0.72 ████0.080.10 ░0.040.06
like0.060.020.10 ░0.070.75 ████
fish0.080.020.80 ████0.050.05

"like" の行に注目してください。英語の2語目 "like" を出すとき、モデルは日本語の文末にある「好き」を見ています。日本語(好きが最後)と英語(likeが2番目)の語順の違いを、cross-attentionが自動的に吸収しているのです。第7章のボトルネック問題(文全体を1本のベクトルに押し込むと細部が失われる)は、「毎ステップ、入力文の全トークンを直接見に行ける」ことで完全に解消されました。

デコーダブロックも N 個積み重ねます。すべてのデコーダブロックのcross-attentionが、エンコーダ塔の最終出力を参照します。


9.9 出力層 — ベクトルを「次のトークンの確率分布」に変える

デコーダ塔のてっぺんから出てくるのは、 dmodel 次元のベクトル(の列)です。しかし私たちが最終的に欲しいのは、第3章以来ずっと追いかけている「次のトークンの確率分布」、すなわち語彙の全単語に対する確率の表です。最後の変換は2段階です。

段階1: 線形層で語彙サイズに広げる。 最後尾トークンのベクトル h(1×dmodel)に、出力行列 Wout(dmodel×Vvocab)を掛けます。

u=hWout

読み下し: dmodel 次元のベクトルを、語彙サイズ Vvocab 次元(数万次元)の「各単語の点数表」に変換する。この点数を ロジット(logit) と呼ぶ。

段階2: softmaxで確率分布にする。

P(次のトークン=w)=softmax(u)w

読み下し: 点数表をsoftmax(第5章)に通し、全単語ぶん足すと1になる確率分布にする。

数値例: 語彙がたった5語 {Cats, like, fish, dogs, EOS} だとして、ロジットが u=(3.2, 1.1, 0.5, 0.8, 0.2) と出たとします。 e3.224.5e1.13.00e0.51.65e0.80.45e0.21.22 、合計 30.8 なので、

候補CatslikefishdogsEOS
ロジット3.21.10.5−0.80.2
確率0.7950.0970.0530.0150.040

読み下し: モデルは「次はCats」に79.5%の確信を持っている。この分布から1語を選べば(選び方は第14章)、次のトークンが決まる。

ちなみに Wout の形(dmodel×Vvocab)は、第6章の埋め込み行列 E(Vvocab×dmodel)の転置と同じです。実際、 Wout=E として同じ行列を入口と出口で共有するモデルも多くあります(重み共有)。「単語→ベクトル」の辞書を逆引きすれば「ベクトル→単語らしさ」になる、という感覚に合ううえ、パラメータを大きく節約できます。


9.10 通し翻訳ストーリー — 「猫は魚が好き」が "Cats like fish" になるまで

それでは、完成したTransformerの中を、データが入口から出口まで流れる様子を通しで追いましょう。

【エンコーダ側: 読解】

  1. トークン化(第6章): 「猫は魚が好き」→ [猫, は, 魚, が, 好き] → ID列 [3049, 12, 887, 30, 2214]
  2. 埋め込み: 埋め込み行列 E から各IDの行を取り出し、5本の dmodel 次元ベクトル、すなわち 5×dmodel の行列 X を作る
  3. 位置エンコーディング(9.3): 各行に位置ベクトル p0,,p4 を足す。これで「魚は3番目」という情報が入った
  4. エンコーダブロック × N(9.7): 各ブロックで「self-attentionで混ぜる→FFNで考える」(残差とLayerNorm付き)を繰り返す。1層目で「好き」のベクトルに主語「猫」と対象「魚」の情報が混ざり、層を経るごとに「猫が主語で、魚が好意の対象で……」という文全体の構造を織り込んだ5本のベクトルに育つ
  5. エンコーダの最終出力(5本のベクトル列)が、全デコーダブロックのcross-attentionにキーとバリューの材料として供給される。エンコーダの仕事はここまで(入力文が変わらない限り、再計算は不要)

【デコーダ側: 作文】 出力文はまだ空です。文の始まりを表す特殊トークン BOS(Beginning of Sequence、文頭記号) だけを置いてスタートします。

  1. ステップ1: デコーダに [BOS] を入れる。埋め込み+位置エンコーディングの後、マスク付きself-attention(トークンが1個なので実質何もしない)→ cross-attentionで入力文を見る。「文頭でまず主語を出すべきだ」→ 重みが「猫」に集中 → 「猫」の情報を取り込む → FFN → …… → 出力層で確率分布(9.9の数値例がまさにこれ)→ "Cats"(79.5%)を選ぶ
  2. ステップ2: デコーダに [BOS, Cats] を入れる。"Cats" の位置のベクトルが、cross-attentionで「好き」を強く見る(9.8の表の "like" の行)→ 確率分布 → "like" を選ぶ
  3. ステップ3: [BOS, Cats, like] を入れる。マスク付きself-attentionで "like" が "Cats" を確認し(単数ならlikesだが複数だからlike、のような整合もここで保たれる)、cross-attentionは「魚」を見る → "fish" を選ぶ
  4. ステップ4: [BOS, Cats, like, fish] を入れる。入力文の内容はすべて訳し終えた → モデルは文の終わりを表す特殊トークン EOS(End of Sequence、文末記号) に最大の確率を割り当てる → 生成終了
ステップデコーダへの入力cross-attentionが主に見る入力語出力(確率最大のトークン)
1BOSCats
2BOS, Cats好きlike
3BOS, Cats, likefish
4BOS, Cats, like, fish文全体EOS(完成)

翻訳結果 "Cats like fish" が得られました。1トークンずつ、毎回「これまでの出力+入力文全体」を材料に次の1語を選ぶ。この生成ループの詳細(確率分布からどう選ぶか、など)は第14章で掘り下げます。

ここで一つ、先の章への伏線を張っておきます。この「デコーダが1トークンずつ次を予測する」部分だけを取り出し、エンコーダとcross-attentionを取り払った構成。実はそれがGPTです(第11章)。あなたはすでに、ChatGPTの本体の設計図をほぼ理解しています。


9.11 パラメータはどこにあるのか — 一覧表と概算

第4章以来、「学習=良いパラメータ探し」と言い続けてきました。ではTransformerの「学習されるパラメータ」は、結局どこに何個あるのでしょうか。全部品を棚卸しします(sin/cos版の位置エンコーディングは計算式で作るのでパラメータなし。学習型ならここにも表が1枚加わります)。

パラメータある場所役割
埋め込み行列 EVvocab×dmodel入口(出口と共有可)トークンID→ベクトル
WQ,WK,WVdmodel×dmodel各attention3つの顔を作る変換
WOdmodel×dmodel各attentionヘッドのメモを混ぜる
FFNの W1,b1dmodel×dffdff各FFN広げて考える
FFNの W2,b2dff×dmodeldmodel各FFN畳んで戻す
LayerNormの γ,βdmodel各LayerNormスケールの微調整
出力層 Woutdmodel×Vvocab出口(E と共有可)ベクトル→語彙の点数表

WQ などは「全ヘッド分をまとめて1枚」と数えています(h 個の dmodel×dk を横に並べると dmodel×dmodel になる。 dk=dmodel/h のため)。

原論文の標準設定(Transformer base)で実際に数えてみましょう。設定は dmodel=512h=8dff=2048N=6(エンコーダ・デコーダ各6層)、語彙 Vvocab=32,000(入口と出口で共有)とします。

  • 埋め込み: 32,000×512=16,384,0001,638 万個
  • attention 1個あたり: WQ,WK,WV,WO の4枚 × 512×512=262,144 で、約 105 万個
  • FFN 1個あたり: 512×2048+2048×512+2048+512=2,099,712210 万個
  • エンコーダブロック1個: attention 1個 + FFN 1個 + LayerNorm 2個 105+210+0.2315 万個 → 6層で約1,890万個
  • デコーダブロック1個: attention 2個(self + cross)+ FFN 1個 + LayerNorm 3個 420 万個 → 6層で約2,520万個
  • 出力層: 埋め込みと共有するので追加ゼロ
合計1,638+1,890+2,5206,000

読み下し: 原論文のTransformer(base)の学習パラメータは約6千万個。論文公称の約6,500万個と(語彙数などの細部の差を除き)一致する。

この6千万個の数字が、すべて第4章の勾配降下法で、翻訳データから少しずつ調整されていきます。そして本書の後半で見るように、この同じ設計図のまま dmodelN と訓練データを増やしていった先に、パラメータ数十億〜数千億個のLLMがあります(GPT-3は1,750億個。規模の話は第13章で)。設計図はもう、あなたの手元にあるのと同じものです。


この章のまとめ

  • Transformerは2017年の論文 "Attention Is All You Need" で提案された、RNNを使わずattentionだけで組んだエンコーダ・デコーダ型の翻訳モデル。並列訓練が可能になったことが、後の大規模化への道を開いた
  • 位置エンコーディング: attentionは語順を完全に無視する(語順を入れ替えても各トークンの出力は不変)ため、周期の異なるsin/cos波の値(または学習型の位置埋め込み)を埋め込みに足して位置情報を注入する
  • 残差接続 y=x+f(x): 微分に必ず「1」が残るため、勾配が層を素通りして深部まで届く「高速道路」。深い積み重ねを可能にする
  • LayerNorm: 各トークンのベクトルを平均0・ばらつき1に整え、学習を安定させる。現代はPre-LN(部品の前に置く)が主流
  • FFN: 各トークンに独立に適用される2層NN(中間層は4倍幅)。attention=混ぜる係、FFN=考える係という分業。知識の貯蔵庫でもある
  • エンコーダブロック = self-attention + FFN(+残差・LayerNorm)。入出力が同じ形なので N 個積める
  • デコーダブロック = マスク付きself-attention + cross-attention + FFN。cross-attentionは「Qをデコーダから、K/Vをエンコーダから」作るattentionで、第7章のseq2seq attentionの正体。ボトルネック問題を解消する
  • 出力層: 線形層でロジット(語彙全体の点数表)を作り、softmaxで次トークンの確率分布にする。埋め込み行列との重み共有も使われる
  • パラメータは埋め込み・ WQ,WK,WV,WO ・FFN・LayerNorm・出力層に分布し、原論文の標準設定で約6千万個。これらすべてが勾配降下法で学習される

次の章へ

設計図は完成しました。しかし、6千万個(LLMなら数千億個)のパラメータに「良い値」を入れる作業、すなわち訓練はどう行うのでしょうか。次章では、「文章そのものが問題と答えになる」自己教師あり学習という仕組みと、因果マスクのおかげで全位置を同時に採点できるカラクリ、そしてGPU数千枚を数ヶ月動かす訓練の実際を見ていきます。

第10章 Transformerを訓練する