Self-Attention — 文脈を捉える中核メカニズム
Transformerの最大の革新はSelf-Attention(自己注意機構)です。 RNNやLSTMが逐次的にトークンを処理していたのに対し、Self-Attentionは入力系列のすべてのトークン間の関係を一度に並列で計算します。 「この単語は文中のどの単語と関連が深いか」を、モデルが学習によって自ら発見する仕組みです。
Query・Key・Value — 3つの役割
Self-Attentionでは、各トークンの埋め込みベクトルを3つの異なる線形変換で射影し、 Query(Q)、Key(K)、Value(V)を生成します。
- Query(問い合わせ): 「自分はどのトークンに注目すべきか?」を表すベクトル
- Key(鍵): 「自分はどのようなQueryに応答すべきか?」を表すベクトル
- Value(値): 実際に集約される情報を持つベクトル
直感的には、図書館での検索に例えられます。Queryは「探している本のテーマ」、Keyは「各本の背表紙に書かれたキーワード」、Valueは「本の中身」です。 QueryとKeyの一致度が高いほど、そのValueが最終的な出力に強く反映されます。
Scaled Dot-Product Attention
Self-Attentionの計算は以下の数式で表されます:
Attention(Q, K, V) = softmax(Q × K^T / √d_k) × V
ここで:
Q: Query行列 (n × d_k)
K: Key行列 (n × d_k)
V: Value行列 (n × d_v)
d_k: Keyベクトルの次元数
√d_k: スケーリング係数 計算の流れを段階的に見てみましょう:
- Q × KT: QueryとKeyの内積を計算し、各トークンペア間の類似度(attention score)を得る
- ÷ √dk: スコアをスケーリングする(後述の理由)
- softmax: スコアを確率分布に変換する(合計が1になる重み)
- × V: 重み付き和でValueを集約し、文脈を反映した新しい表現を得る
Multi-Head Attention — 多角的な視点を同時に学ぶ
単一のSelf-Attentionでは、1つの「視点」でしかトークン間の関係を捉えられません。 しかし自然言語には、構文的な関係(主語-述語)、意味的な関係(同義語・反義語)、共参照関係(代名詞が指す先)など、 複数の異なるパターンが同時に存在します。
Multi-Head Attentionはこの問題を解決します。 Q・K・Vをそれぞれh個のヘッドに分割し、各ヘッドが独立にSelf-Attentionを計算します。 最後に全ヘッドの出力を結合(concat)し、線形変換で元の次元に戻します。
MultiHead(Q, K, V) = Concat(head_1, ..., head_h) × W^O
head_i = Attention(Q × W_i^Q, K × W_i^K, V × W_i^V)
例: d_model = 768, h = 12 の場合
各ヘッドの次元: d_k = 768 / 12 = 64
計算コストは単一ヘッド(d_model=768)と同等 重要なのは、ヘッド数を増やしても計算コストがほぼ変わらない点です。 d_model を h 個に分割するため、各ヘッドの次元は d_model / h となり、 全体の計算量は単一の大きなAttentionとほぼ同じです。 それでいて、各ヘッドが異なるパターンを専門的に学習できるのです。
graph TD Input[入力埋め込み\nd_model = 768] --> Split[h個のヘッドに分割] Split --> H1[Head 1\n構文パターン\nd_k = 64] Split --> H2[Head 2\n意味パターン\nd_k = 64] Split --> H3[Head 3\n共参照パターン\nd_k = 64] Split --> Hdots[... Head h] H1 --> Concat[Concat + 線形変換 W^O] H2 --> Concat H3 --> Concat Hdots --> Concat Concat --> Output[出力\nd_model = 768] style Input fill:#3b82f6,stroke:#1d4ed8,color:#fff style Split fill:#6366f1,stroke:#4f46e5,color:#fff style H1 fill:#8b5cf6,stroke:#6d28d9,color:#fff style H2 fill:#8b5cf6,stroke:#6d28d9,color:#fff style H3 fill:#8b5cf6,stroke:#6d28d9,color:#fff style Hdots fill:#8b5cf6,stroke:#6d28d9,color:#fff style Concat fill:#6366f1,stroke:#4f46e5,color:#fff style Output fill:#3b82f6,stroke:#1d4ed8,color:#fff
Feed-Forward Network — 非線形変換による表現力の増幅
Transformerの各レイヤーは、Multi-Head Attentionの後にFeed-Forward Network(FFN)を持ちます。 FFNは各トークンに対して独立に適用される2層の全結合ネットワークです。
FFN(x) = GELU(x × W_1 + b_1) × W_2 + b_2
ここで:
W_1: d_model → d_ff (拡張: 通常 d_ff = 4 × d_model)
W_2: d_ff → d_model (圧縮: 元の次元に戻す)
GELU: 活性化関数(ReLUの滑らかな近似)
例: d_model = 768 の場合
d_ff = 3072 (= 768 × 4)
W_1 で768次元 → 3072次元に拡張
W_2 で3072次元 → 768次元に圧縮 なぜ一度4倍に拡張してから元に戻すのでしょうか? 高次元空間では、データの非線形なパターンをより豊かに表現できます。 Attentionが「どのトークンの情報を集めるか」を決める情報の集約であるのに対し、 FFNは集約された情報に対して非線形変換を加え、抽象的な特徴を抽出する役割を担っています。
Transformerブロックの全体構造
ここまでの要素を組み合わせた1つのTransformerブロックの構造を図示します。 実際のLLMは、このブロックを数十〜百層以上積み重ねたものです。
graph TD Input[入力トークン埋め込み + 位置エンコーディング] --> LN1[Layer Normalization] LN1 --> MHA[Multi-Head Attention] MHA --> Add1[残差接続 +] Input --> Add1 Add1 --> LN2[Layer Normalization] LN2 --> FFN[Feed-Forward Network\nGELU活性化 / 4倍拡張] FFN --> Add2[残差接続 +] Add1 --> Add2 Add2 --> Output[次のブロックへ / 最終出力] style Input fill:#3b82f6,stroke:#1d4ed8,color:#fff style LN1 fill:#64748b,stroke:#475569,color:#fff style MHA fill:#8b5cf6,stroke:#6d28d9,color:#fff style Add1 fill:#f97316,stroke:#ea580c,color:#fff style LN2 fill:#64748b,stroke:#475569,color:#fff style FFN fill:#8b5cf6,stroke:#6d28d9,color:#fff style Add2 fill:#f97316,stroke:#ea580c,color:#fff style Output fill:#3b82f6,stroke:#1d4ed8,color:#fff
残差接続(Residual Connection)は、入力をそのまま出力に加算するショートカットです。 これにより深い層でも勾配が伝播しやすくなり、100層以上のモデルの学習を可能にしています。 Layer Normalizationは各層の出力を正規化し、学習を安定させます。
アーキテクチャの分類 — Decoder-only が主流になった理由
Transformerベースのモデルは、大きく3つのアーキテクチャに分類されます。
| アーキテクチャ | 代表モデル | 入力の注意範囲 | 主な用途 | 現在の位置づけ |
|---|---|---|---|---|
| Encoder-only | BERT, RoBERTa | 双方向(前後すべてのトークン) | 分類・固有表現抽出・文埋め込み | 特化タスクで現役 |
| Encoder-Decoder | T5, BART, mBART | Encoder双方向 + Decoder因果的 | 翻訳・要約・質問応答 | 一部で利用 |
| Decoder-only | GPT系, LLaMA, Claude, Gemini | 因果的(左から右のみ) | テキスト生成全般 | LLMの主流 |
なぜDecoder-onlyがLLMの主流になったのでしょうか? 主な理由は3つあります:
- スケーリングとの相性: Decoder-onlyは「次のトークンを予測する」という単一タスクに特化しているため、 パラメータ数やデータ量を増やすほど性能が向上するスケーリング則と相性が良い
- 統一的なインターフェース: 翻訳も要約も質問応答も、すべて「テキスト生成」として扱えるため、 タスク固有のヘッドを設計する必要がない
- 効率的な学習: 因果的マスク(Causal Mask)により、1つの入力系列から複数の予測を同時に学習できる。 入力が n トークンなら n-1 個の予測タスクを一度に学習可能
トークナイゼーション — テキストをモデルが扱える単位に分割する
LLMは文字列をそのまま入力できません。テキストをトークンと呼ばれる離散的な単位に分割し、 それぞれを数値IDに変換するプロセスがトークナイゼーションです。
| 手法 | 代表的な採用モデル | 仕組み | 特徴 |
|---|---|---|---|
| BPE (Byte Pair Encoding) | GPT系, LLaMA | 頻出するバイト/文字ペアを繰り返し統合 | 未知語に強い、サブワード分割の標準 |
| WordPiece | BERT, DistilBERT | 尤度ベースでサブワードを選択 | BPEに似るが統合基準が異なる |
| SentencePiece | T5, LLaMA, Gemini | 言語非依存の前処理不要分割 | 日本語や中国語などスペース区切りがない言語に有効 |
| Byte-level BPE | GPT-4, Claude | UTF-8バイト列上でBPEを適用 | あらゆる言語・記号を扱える万能性 |
日本語のトークン膨張問題
英語中心で訓練されたトークナイザでは、日本語テキストが英語の2〜3倍のトークン数に膨張する問題があります。 英語の "artificial intelligence" が2トークンで表現できるのに対し、「人工知能」は3〜4トークンに分割されることがあります。
# GPT-4のトークナイゼーション例(概算)
英語: "The transformer architecture is powerful"
→ ["The", " transform", "er", " architecture", " is", " powerful"]
→ 6トークン
日本語: "Transformerアーキテクチャは強力だ"
→ ["Trans", "former", "ア", "ーキ", "テ", "ク", "チャ", "は", "強", "力", "だ"]
→ 11トークン(英語の約1.8倍) トークン膨張はコスト増(APIは通常トークン単位課金)とコンテキスト長の実質的な圧縮を招きます。 この問題を軽減するため、LLaMA 3やGeminiでは日本語を含む多言語データでトークナイザを訓練し、 日本語のトークン効率を大幅に改善しています。
位置エンコーディング — 語順の情報をモデルに与える
Self-Attentionは本質的に順序を考慮しない演算です。 「猫が魚を食べた」と「魚が猫を食べた」は、Attention計算だけでは区別できません。 そこで、トークンの位置情報を明示的にモデルに注入する位置エンコーディングが必要になります。
| 手法 | 提案年 / 論文 | 仕組み | 特徴 |
|---|---|---|---|
| Sinusoidal | 2017 / Attention Is All You Need | 正弦・余弦関数で固定的な位置ベクトルを生成 | 学習不要だが、訓練長を超える外挿が苦手 |
| 学習可能な位置埋め込み | GPT-2, BERT | 各位置にパラメータとして埋め込みを学習 | 柔軟だが最大系列長が固定される |
| RoPE (Rotary Position Embedding) | 2021 / LLaMA, Qwen, Mistral | Q・Kベクトルを位置に応じて回転 | 現在の主流。相対位置を自然にエンコード |
| ALiBi (Attention with Linear Biases) | 2021 / BLOOM, MPT | Attentionスコアに距離に比例したバイアスを加算 | 外挿性能に優れ、追加パラメータ不要 |
RoPE — なぜ主流になったのか
RoPE(Rotary Position Embedding)は、QueryとKeyのベクトルを位置に応じた角度で回転させます。 2つのトークンのAttentionスコアは、それぞれの絶対位置ではなく相対的な距離にのみ依存するようになります。
RoPEが主流になった理由は以下の通りです:
- 相対位置の自然なエンコード: 「3トークン離れている」という関係を回転角度の差として表現
- 長文への拡張性: NTK-Aware Scalingなどの手法で、訓練時より長い系列にも対応可能
- 実装の効率性: 複素数の回転演算として高速に計算でき、追加パラメータも不要
LLaMA、Mistral、Qwen、Gemma など、2024年以降のほぼすべてのオープンソースLLMがRoPEを採用しています。
理解度チェック
Scaled Dot-Product Attentionで √d_k によるスケーリングを行う主な理由は何ですか?
キーボード: 1〜4 で選択、Enter で回答