LESSON

Transformerアーキテクチャ

田中VPoE:「Attention 機構を理解したところで、次は Transformer 全体のアーキテクチャを見ていこう。2017年に “Attention Is All You Need” という論文で提案されたモデルで、RNN を完全に置き換えた。」

あなた:「“Attention がすべて” って大胆なタイトルですね。RNN なしで系列データを処理するって当時は衝撃だったんじゃないですか。」

田中VPoE:「その通り。並列計算が可能になり、学習速度が劇的に向上した。現在の GPT や BERT は全て Transformer ベースだ。NetShop のレビュー分析にも直結する技術だよ。」

Transformer の全体構造

Transformer は Encoder(エンコーダ)と Decoder(デコーダ)の2つの部分から構成されます。

入力系列 → [Encoder] → 文脈表現 → [Decoder] → 出力系列

Encoder: 入力を文脈を考慮した表現に変換
Decoder: Encoder の出力を参照しながら出力を生成

Encoder ブロック

入力

[Multi-Head Self-Attention]
  ↓  ← Add & Norm(残差接続 + 層正規化)
[Feed-Forward Network]
  ↓  ← Add & Norm
出力

Decoder ブロック

出力(シフト済み)

[Masked Multi-Head Self-Attention]
  ↓  ← Add & Norm
[Multi-Head Cross-Attention]  ← Encoder の出力を参照
  ↓  ← Add & Norm
[Feed-Forward Network]
  ↓  ← Add & Norm
出力

位置エンコーディング

Transformer は RNN と異なり、入力の順序情報を持ちません。そのため、位置エンコーディングで位置情報を付加します。

import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)
        )
        pe[:, 0::2] = torch.sin(position * div_term)  # 偶数次元: sin
        pe[:, 1::2] = torch.cos(position * div_term)  # 奇数次元: cos
        pe = pe.unsqueeze(0)  # (1, max_len, d_model)
        self.register_buffer('pe', pe)

    def forward(self, x):
        # x: (batch, seq_len, d_model)
        return x + self.pe[:, :x.size(1), :]
位置エンコーディングの特性:
- 各位置に固有のパターンを割り当てる
- sin/cos の組み合わせにより、相対位置の関係も捉えられる
- 学習不要(固定値)で、任意の長さに対応可能

Encoder の実装

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.self_attn = nn.MultiheadAttention(d_model, num_heads, dropout=dropout, batch_first=True)
        self.feed_forward = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model),
        )
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # Self-Attention + Add & Norm
        attn_output, _ = self.self_attn(x, x, x, attn_mask=mask)
        x = self.norm1(x + self.dropout(attn_output))

        # Feed-Forward + Add & Norm
        ff_output = self.feed_forward(x)
        x = self.norm2(x + self.dropout(ff_output))

        return x

class TransformerEncoder(nn.Module):
    def __init__(self, vocab_size, d_model=512, num_heads=8,
                 d_ff=2048, num_layers=6, dropout=0.1):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model)
        self.layers = nn.ModuleList([
            TransformerEncoderLayer(d_model, num_heads, d_ff, dropout)
            for _ in range(num_layers)
        ])
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        x = self.embedding(x) * math.sqrt(self.embedding.embedding_dim)
        x = self.pos_encoding(x)
        x = self.dropout(x)

        for layer in self.layers:
            x = layer(x, mask)

        return x

Transformer の主要コンポーネント

コンポーネント役割詳細
Embeddingトークンをベクトルに変換語彙サイズ → d_model 次元
Positional Encoding位置情報の付加sin/cos 関数で固定パターン
Multi-Head Attention多角的な関係性の学習並列計算で高速化
Feed-Forward Network非線形変換2層の全結合 + ReLU
Layer Normalization学習の安定化各層の出力を正規化
Residual Connection勾配消失の防止入力を出力に加算

RNN と Transformer の比較

特性RNN / LSTMTransformer
並列計算不可(逐次処理)可能(大幅な高速化)
長距離依存苦手(勾配消失)得意(直接参照)
計算量O(n)O(n^2)(系列長の2乗)
メモリ系列長に比例系列長の2乗に比例
学習速度遅い速い(GPU 活用)

PyTorch の Transformer API

PyTorch には Transformer の組み込み実装があります。

# PyTorch 組み込みの Transformer Encoder
encoder_layer = nn.TransformerEncoderLayer(
    d_model=512,
    nhead=8,
    dim_feedforward=2048,
    dropout=0.1,
    batch_first=True
)
transformer_encoder = nn.TransformerEncoder(
    encoder_layer,
    num_layers=6
)

# 使用例
x = torch.randn(32, 100, 512)  # (batch, seq_len, d_model)
output = transformer_encoder(x)
print(f"出力: {output.shape}")  # (32, 100, 512)

まとめ

  • Transformer は Attention のみで系列データを処理するアーキテクチャ
  • Encoder と Decoder の2部構成で、各ブロックは Attention + FFN + Add&Norm
  • 位置エンコーディングで系列の順序情報を付加する
  • RNN と比べて並列計算が可能で、長距離依存の学習にも優れる
  • GPT、BERT など現代の言語モデルの基盤技術

チェックリスト

  • Transformer の全体構造(Encoder / Decoder)を説明できる
  • 位置エンコーディングの必要性を理解した
  • Encoder ブロックの構成要素を列挙できる
  • RNN と比較した Transformer の利点を説明できる

推定読了時間: 30分