深層学習とLLM

目次

概要

表現学習、ニューラルネット、Transformerをひとつの流れで理解する

深層学習は、多層の表現変換を通じて複雑な関係を学ぶ方法です。現在のLLMは、その延長線上でTransformerと大規模事前学習を組み合わせたものとして理解できます。この章では、ニューラルネットの基本から、正則化、表現学習生成モデル、LLMまでをつなげて整理します。

要点

深層学習の本質は「特徴量を人が全部作るのではなく、表現そのものを学ぶ」点にあります。LLMはその延長線上にある、大規模な系列モデルです。

この章で重視すること

  • ニューラルネットを、重み付き計算と非線形変換の繰り返しとして捉える
  • 深層学習と古典的機械学習の違いを、表現学習の有無で整理する
  • LLMを単体モデルではなく、学習・推論・評価・運用を含むシステムとして見る

深層学習とは何か

古典的機械学習では、人が特徴量を強く設計することが多くありました。深層学習では、その特徴表現そのものを多層ネットワークで学びます。

flowchart LR A["生データ"] --> B["多層の表現変換"] B --> C["高水準の表現"] C --> D["予測 / 生成"]

この違いが、画像、音声、自然言語のような高次元データで深層学習が強い理由です。

ニューラルネットワークの基本

最も基本的な構造は、

  • 線形変換
  • 非線形活性化
  • 層の積み重ね

です。

多層パーセプトロン(MLP)は、この最小形として理解しやすいモデルです。ここで重要なのは、層を重ねることで単純な線形モデルでは表せない関係を扱えるようになる点です。

逆伝播と学習

深層学習では、損失を減らすために各重みを更新します。逆伝播は、そのために「どの重みがどのくらい損失に効いたか」を連鎖律で後ろから伝える仕組みです。

flowchart LR A["順伝播"] --> B["損失"] B --> C["逆伝播"] C --> D["勾配"] D --> E["重み更新"]

ここで学ぶべき点は、

  • 勾配が流れること
  • 深くなると不安定になりやすいこと
  • 最適化と初期化が重要になること

です。

正則化と安定化

深層学習では、表現力が高いぶん、過学習や不安定さも大きくなります。代表的な対策は次です。

  • weight decay
  • dropout
  • batch normalization / layer normalization
  • early stopping
  • データ拡張

正則化は単に「性能を落とさないための保険」ではなく、未知データで壊れにくいモデルを作るための設計要素です。

表現学習

表現学習は、入力を別の空間に埋め込み、扱いやすい特徴へ変換する考え方です。

  • 埋め込みベクトル
  • オートエンコーダ
  • 自己教師あり学習

画像、音声、自然言語では、この「どんな表現空間を学ぶか」が性能を大きく左右します。

生成モデル

生成モデルは、データを分類するのではなく、データの分布や生成過程を学びます。

代表例:

  • Autoencoder / VAE
  • GAN
  • Diffusion Model

生成モデルを学ぶと、「入力からラベルを当てる」以外のAIの見方が広がります。

Transformer

Transformerは、系列データを扱う現代の中心的な構造です。自己注意機構によって、系列内のどの位置同士が強く関係するかを学びます。

flowchart LR A["トークン列"] --> B["埋め込み"] B --> C["自己注意"] C --> D["フィードフォワード"] D --> E["次トークン予測 / 表現出力"]

RNNと比べたときの利点:

  • 並列化しやすい
  • 長距離依存を扱いやすい
  • スケールしやすい

Vaswani et al. (2017) により発表された「Attention Is All You Need」は、再帰や畳み込みを完全に排除し、注意機構のみに基づく新しいシンプルなネットワークアーキテクチャを提案しました。機械翻訳タスクでは28.4 BLEUを達成し、既存の最良結果を2 BLEU以上改善し、同時により並列化しやすく、大幅に少ない訓練時間で完了しました。

Transformer の詳細構造

Self-Attentionの仕組み

Self-Attentionは、各トークンが他のすべてのトークンを参照しながら、文脈に応じた表現を構築します。Query、Key、Valueの3つの行列を用いて計算されます。

flowchart LR T["トークン列"] Q["Query 計算"] K["Key 計算"] V["Value 計算"] S["スコア計算"] A["Attention 重み"] O["出力"] T --> Q T --> K T --> V Q --> S K --> S S --> A A --> O V --> O

Self-Attentionの数学的表現:

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

スケーリング係数 dk\sqrt{d_k} は、内積の大きさが次元に応じて変わることを補正します。

Multi-Head Attention

複数の注意ヘッドを並列に実行することで、異なるサブスペース上で相互作用をキャプチャします。

  • 単一ヘッド: 1つの線形変換
  • マルチヘッド: 複数の線形変換を並列実行して結合

これにより、各ヘッドが異なる種類の関係性(文法的、意味的など)を学習できます。

Positional Encoding

トークンの順序情報を組み込むため、絶対位置または相対位置にもとづいたPositional Encodingを追加します。

正弦波ベースの位置符号化:

PE(pos,2i)=sin(pos/100002i/dmodel)PE_{(pos, 2i)} = \sin(pos / 10000^{2i/d_{\text{model}}})

PE(pos,2i+1)=cos(pos/100002i/dmodel)PE_{(pos, 2i+1)} = \cos(pos / 10000^{2i/d_{\text{model}}})

この設計により、相対位置に関する線形な関係が学習しやすくなります。

層の積み重ね構造

Transformerは、Encoder層と Decoder層をそれぞれ複数スタックします。

  • Encoder: 入力全体をコンテキスト化
  • Decoder: 出力を自動回帰的に生成、Encoderの出力を参照

各層は以下を含みます:

  1. Multi-Head Self-Attention + Residual接続 + Layer Norm
  2. Feed-Forward Network (FFN) + Residual接続 + Layer Norm

Residual接続と Layer Normalization は、深いモデルの学習を安定化させます。

LLMの基本構造

LLMは、巨大なテキストコーパスで次トークン予測を学ぶ大規模Transformerです。

理解の軸は次の通りです。

  • トークン化
  • 埋め込み
  • Attention
  • コンテキスト長
  • 事前学習
  • 推論時のdecoding

LLMを「知識を持った箱」と見るよりも、「系列上の条件付き確率モデル」として見る方が、限界や失敗も理解しやすくなります。

LLMアーキテクチャの進化

BERT時代 (2018)

BERT(「BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding」、Devlin et al. 2018)は、事前学習タスクとして Masked Language Modeling (MLM) と Next Sentence Prediction (NSP) を導入しました。

双方向性により、文脈の両側から情報を取得でき、下流タスク(分類、固有表現認識など)で高い性能を実現しました。

Decoder-Only モデルへの転換

GPTシリーズの成功により、Decoder-Onlyアーキテクチャが主流に。

  • 次トークン予測のみで事前学習
  • 自動回帰生成に最適化
  • スケーリング法則がシンプル

現代の実装特性

多くの最新LLMは次の工夫を含みます:

  • RoPE(Rotary Position Embedding): 相対位置符号化の改善版
  • Flash Attention: 計算効率を大幅改善
  • Group Query Attention(GQA): KVキャッシュのメモリ削減

これらは、より長いコンテキストと効率的な推論を実現しています。

LLMの学習と適応

LLMを使う流れは、大きく

  • 事前学習
  • 指示追従の調整
  • 追加学習 / ファインチューニング
  • 推論時の外部知識利用

に分かれます。

ここで重要なのは、モデル本体だけでなく、

  • SFT (Supervised Fine-Tuning)
  • PEFT / LoRA (Parameter-Efficient Fine-Tuning)
  • RAG (Retrieval-Augmented Generation)
  • 推論時プロンプト設計

といった外側の工夫も含めて性能が決まることです。

Transformer アーキテクチャの詳細

Self-Attention の計算

Self-Attention は Query、Key、Value ベクトルを用いたシーケンス内の関連性計算。

import numpy as np
import torch
import torch.nn as nn

def scaled_dot_product_attention(Q, K, V, mask=None):
    """
    Scaled Dot-Product Attention
    
    Args:
        Q: Query [batch_size, seq_len, d_k]
        K: Key [batch_size, seq_len, d_k]
        V: Value [batch_size, seq_len, d_v]
        mask: Optional mask [seq_len, seq_len]
    """
    d_k = Q.shape[-1]
    
    # 1. Compute attention scores
    scores = torch.matmul(Q, K.transpose(-2, -1)) / np.sqrt(d_k)
    # Shape: [batch_size, seq_len, seq_len]
    
    # 2. Apply mask (for causal/future masking)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, -1e9)
    
    # 3. Apply softmax
    attention_weights = torch.softmax(scores, dim=-1)
    
    # 4. Multiply by values
    output = torch.matmul(attention_weights, V)
    # Shape: [batch_size, seq_len, d_v]
    
    return output, attention_weights

複雑度分析:

  • Time: O(n^2 * d)(n=シーケンス長、d=隠れ次元)
  • Space: O(n^2)(attention 行列)

長いシーケンス(4096+ トークン)では計算量が支配的。

Multi-Head Attention

複数の"ヘッド"を並列に実行し、異なる部分空間で関連性を学習。

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, n_heads):
        super().__init__()
        assert d_model % n_heads == 0
        
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads  # 各ヘッドの次元
        
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
    
    def forward(self, Q, K, V, mask=None):
        batch_size = Q.shape[0]
        
        # Linear transformations
        Q = self.W_q(Q).reshape(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        K = self.W_k(K).reshape(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        V = self.W_v(V).reshape(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        # Shape: [batch_size, n_heads, seq_len, d_k]
        
        # Scaled dot-product attention
        attn_output, attn_weights = scaled_dot_product_attention(Q, K, V, mask)
        
        # Concatenate heads
        attn_output = attn_output.transpose(1, 2).reshape(batch_size, -1, self.d_model)
        
        # Final linear layer
        output = self.W_o(attn_output)
        
        return output, attn_weights

Feed-Forward Network

class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff, dropout=0.1):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model),
            nn.Dropout(dropout)
        )
    
    def forward(self, x):
        return self.net(x)

Positional Encoding

Transformer は位置情報を別途エンコードする(RNN と異なり)。

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_seq_len=5000):
        super().__init__()
        
        pe = torch.zeros(max_seq_len, d_model)
        position = torch.arange(0, max_seq_len).unsqueeze(1)  # [max_seq_len, 1]
        
        # 正弦・余弦関数の周期を異なる周波数で
        div_term = torch.exp(torch.arange(0, d_model, 2) * -(np.log(10000) / d_model))
        
        pe[:, 0::2] = torch.sin(position * div_term)      # 偶数インデックス
        pe[:, 1::2] = torch.cos(position * div_term)      # 奇数インデックス
        
        self.register_buffer('pe', pe.unsqueeze(0))  # [1, max_seq_len, d_model]
    
    def forward(self, x):
        # x shape: [batch_size, seq_len, d_model]
        return x + self.pe[:, :x.size(1), :]

大言語モデル(LLM)の設計

Decoder-only アーキテクチャ(GPT系)

GPT-3、GPT-4、Llama などは decoder-only 構成。

class TransformerDecoderBlock(nn.Module):
    def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
        super().__init__()
        
        self.self_attn = MultiHeadAttention(d_model, n_heads)
        self.norm1 = nn.LayerNorm(d_model)
        
        self.ffn = FeedForward(d_model, d_ff, dropout)
        self.norm2 = nn.LayerNorm(d_model)
        
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, causal_mask):
        # Self-attention + residual
        attn_out, _ = self.self_attn(x, x, x, mask=causal_mask)
        x = x + self.dropout(attn_out)
        x = self.norm1(x)
        
        # FFN + residual
        ffn_out = self.ffn(x)
        x = x + self.dropout(ffn_out)
        x = self.norm2(x)
        
        return x

class LLMDecoder(nn.Module):
    def __init__(self, vocab_size, d_model, n_layers, n_heads, d_ff, max_seq_len=2048):
        super().__init__()
        
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_seq_len)
        
        self.decoder_layers = nn.ModuleList([
            TransformerDecoderBlock(d_model, n_heads, d_ff)
            for _ in range(n_layers)
        ])
        
        self.norm = nn.LayerNorm(d_model)
        self.output_projection = nn.Linear(d_model, vocab_size)
    
    def forward(self, token_ids, causal_mask):
        # Token embedding + positional encoding
        x = self.embedding(token_ids)
        x = self.pos_encoding(x)
        
        # Apply decoder layers
        for layer in self.decoder_layers:
            x = layer(x, causal_mask)
        
        # Final layer norm
        x = self.norm(x)
        
        # Project to vocabulary
        logits = self.output_projection(x)
        # Shape: [batch_size, seq_len, vocab_size]
        
        return logits

Context Window Management

LLM のコンテキスト長(通常 2048~ 128k トークン)は計算・メモリのボトルネック。

# KV キャッシュ戦略:推論時に計算済み K,V を再利用
class KVCache:
    def __init__(self, max_seq_len, n_heads, d_k):
        self.max_seq_len = max_seq_len
        self.n_heads = n_heads
        self.d_k = d_k
        
        self.k_cache = {}  # layer_id -> [batch, n_heads, seq_len, d_k]
        self.v_cache = {}
    
    def get_or_create(self, layer_id, batch_size):
        if layer_id not in self.k_cache:
            device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
            self.k_cache[layer_id] = torch.zeros(batch_size, self.n_heads, self.max_seq_len, self.d_k, device=device)
            self.v_cache[layer_id] = torch.zeros(batch_size, self.n_heads, self.max_seq_len, self.d_k, device=device)
        
        return self.k_cache[layer_id], self.v_cache[layer_id]
    
    def update(self, layer_id, k_new, v_new, position):
        k_cache, v_cache = self.get_or_create(layer_id, k_new.shape[0])
        k_cache[:, :, position:position+k_new.shape[2], :] = k_new
        v_cache[:, :, position:position+v_new.shape[2], :] = v_new

Token 生成戦略

def generate(model, prompt_tokens, max_new_tokens, temperature=0.7, top_p=0.9):
    """
    Temperature + Top-p sampling を用いた自動回帰生成
    """
    generated = prompt_tokens.copy()
    
    for _ in range(max_new_tokens):
        # モデル実行
        logits = model(generated[-context_window:])
        logits = logits[:, -1, :]  # 最後のトークンの logits
        
        # Temperature scaling
        logits = logits / temperature
        
        # Top-p サンプリング
        probs = torch.softmax(logits, dim=-1)
        sorted_probs, sorted_indices = torch.sort(probs, descending=True)
        cumsum_probs = torch.cumsum(sorted_probs, dim=-1)
        
        # 累積確率が top_p を超えるトークンを除外
        sorted_indices_to_remove = cumsum_probs > top_p
        sorted_indices_to_remove[..., 0] = False  # top token は必ず残す
        
        indices_to_remove = sorted_indices[sorted_indices_to_remove]
        logits[indices_to_remove] = -float('inf')
        
        # サンプリング
        next_token = torch.multinomial(torch.softmax(logits, dim=-1), num_samples=1)
        generated.append(next_token.item())
    
    return generated

効率化テクニック

Quantization(量子化)

16-bit float → 8-bit int への変換で 4倍メモリ削減。精度低下は最小限。

from bitsandbytes.nn import Linear8bitLt

# LoRA + 8bit 量子化
def quantize_and_lora(base_model):
    # 重みを int8 に量子化
    quantized_model = base_model
    for name, module in quantized_model.named_modules():
        if isinstance(module, nn.Linear):
            quantized_model._modules[name] = Linear8bitLt(
                module.in_features,
                module.out_features,
                has_fp16_weights=False,
                threshold=6.0
            )
    
    return quantized_model

Low-Rank Adaptation (LoRA)

大規模モデルの全体 fine-tuning の代わりに、低ランク行列を追加。

class LoRALinear(nn.Module):
    def __init__(self, in_features, out_features, r=8, alpha=16, dropout=0.1):
        super().__init__()
        
        self.weight = nn.Parameter(torch.randn(out_features, in_features) / np.sqrt(in_features))
        self.bias = nn.Parameter(torch.zeros(out_features))
        
        # LoRA: W = W_0 + (A @ B) * alpha / r
        self.A = nn.Parameter(torch.randn(in_features, r) / np.sqrt(in_features))
        self.B = nn.Parameter(torch.zeros(r, out_features))
        
        self.dropout = nn.Dropout(dropout)
        self.r = r
        self.alpha = alpha
    
    def forward(self, x):
        # 元の重み + LoRA 更新
        output = nn.functional.linear(x, self.weight, self.bias)
        
        lora_update = self.dropout(x) @ self.A @ self.B * (self.alpha / self.r)
        output = output + lora_update
        
        return output

# 使用例
# 元の Linear 層を LoRA に置換
for name, module in model.named_modules():
    if isinstance(module, nn.Linear) and 'attn' in name:
        # アテンション層のみ LoRA 化(他より重要)
        parent = model
        for p in name.split('.')[:-1]:
            parent = getattr(parent, p)
        setattr(parent, name.split('.')[-1], LoRALinear(module.in_features, module.out_features))

Flash Attention

メモリバウンドな操作を削減し、計算効率を向上。

# torch >= 2.0 では組み込み
import torch.nn.functional as F

def flash_attention_forward(Q, K, V):
    """
    Flash Attention の効果(メモリ IO 削減)
    
    標準的な Attention: SRAM -> HBM(高バンド幅メモリ)への往復が多い
    Flash Attention: ブロック単位で処理し IO を最小化
    """
    # PyTorch 2.0+
    return F.scaled_dot_product_attention(Q, K, V, is_causal=True)

性能改善例(H100 GPU):

  • 標準実装: 100-200 ms(4k トークン)
  • Flash Attention v2: 10-20 ms(ほぼ 10 倍)

評価メトリクス

Perplexity(困惑度)

訓練済みモデルの言語モデリング能力を測定。

def calculate_perplexity(model, test_dataset):
    """
    PP = exp( -1/N * sum(log P(token_i)) )
    
    低いほど良い(2~ 3 が SOTA, 20+ が悪い)
    """
    total_loss = 0
    total_tokens = 0
    
    model.eval()
    with torch.no_grad():
        for batch in test_dataset:
            logits = model(batch['input_ids'])
            loss = F.cross_entropy(
                logits.view(-1, vocab_size),
                batch['labels'].view(-1),
                reduction='sum'
            )
            total_loss += loss.item()
            total_tokens += batch['labels'].numel()
    
    perplexity = np.exp(total_loss / total_tokens)
    return perplexity

BLEU, ROUGE(生成タスク)

BLEU: n-gram の正確さ(機械翻訳) ROUGE: Recall ベースの一致度(要約)

from torchtext.data.metrics import bleu_score
from rouge_score import rouge_scorer

# BLEU スコア
reference = [["a", "dog", "is", "running"]]
hypothesis = ["a", "dog", "running"]
bleu = bleu_score([hypothesis], reference)  # 0.0~ 1.0

# ROUGE スコア
scorer = rouge_scorer.RougeScorer(['rouge1', 'rougeL'])
ref = "The quick brown fox"
hyp = "A quick brown fox"
scores = scorer.score(ref, hyp)
print(scores['rouge1'].fmeasure)  # F値

LLMの評価と安全性

LLMは「それっぽく話す」ため、評価が難しいモデルです。見るべき観点は複数あります。

  • タスク性能
  • 事実性
  • 一貫性
  • 幻覚
  • レイテンシ
  • コスト
  • 安全性

安全性では、

  • 有害出力
  • 情報漏えい
  • プロンプトインジェクション
  • モデルの過信

を考える必要があります。

GPU章とのつながり

この章はモデルの見方を扱い、GPU 章は実行基盤の見方を扱います。

  • この章: なぜTransformerやLLMが成り立つか
  • GPU章: それをどう高速に推論・提供するか

特に、

  • Attention
  • KV cache
  • バッチング
  • 量子化

は両章をつなぐキーワードです。

Attentionの直感

Transformerの中心にあるself-attentionは、各tokenが他のtokenを参照しながら表現を更新する仕組みです。文の中で何が何に関係しているかを、固定の距離ではなく内容に応じて学習します。

flowchart LR T1["token A"] --> A["attention"] T2["token B"] --> A T3["token C"] --> A A --> R["updated representation"]

RNNでは系列を順番に処理しますが、Transformerは多くの位置を並列に扱いやすい構造です。この性質が、大規模データとGPUによる学習に合いました。

「The Illustrated Transformer」(Jay Alammarによる詳細な図解)は、Transformerの各部分を段階的に視覚化し、Query、Key、Value、Positional Encodingといった概念を直感的に説明しています。Self-Attentionの行列計算、Multi-Head Attentionの役割、各層の残差接続とLayerNormを図と共に理解できます。

学習と推論の違い

LLMでは、学習と推論でボトルネックが変わります。

段階 主な処理 ボトルネック
事前学習 大量tokenで重みを更新する 計算量、通信、データ供給
instruction tuning 指示応答データで調整する データ品質、過適応
推論prefill prompt全体を処理する context length、attention計算
推論decode 1tokenずつ生成する memory bandwidth、KV cache

GPU章で扱うKV cacheやbatchingは、特に推論時のdecodeを効率化するために重要です。

Fine-tuning、RAG、promptingの使い分け

LLMを業務へ合わせる方法は複数あります。

方法 向いていること 注意点
prompting 出力形式や作業手順の調整 知識更新には弱い
RAG 外部文書にもとづく回答 検索品質に依存する
fine-tuning 文体、分類、特定タスクの安定化 データ品質と評価が重要
tool use 計算、検索、操作 権限と安全設計が必要

まずRAGやpromptingで足りるかを確認し、モデル自体の振る舞いを継続的に変えたい場合にfine-tuningを検討します。

評価の分解

LLM評価では、1つのスコアで全体を判断しない方が安全です。

  • 正確性
  • 根拠への忠実性
  • 指示追従
  • 安全性
  • 一貫性
  • レイテンシ
  • コスト
  • 回帰の有無

特に「人間には自然に見えるが、根拠がない」回答を検出するには、検索結果、引用、期待回答を分けて評価します。

LLM スケーリングと推論最適化

Chinchilla スケーリング則

最適なトークン数: N_opt = 20 * N_params。70B パラメータ → 1.4T トークン。Loss(N,D) ≈ E/N^α + B/D^β で α≈0.07, β≈0.16。パラメータ 2 倍で Loss 7%低下、トークン 2 倍で Loss 16%低下。

推論最適化

バッチサイズ 1 は遅延 100ms・スループット 10tokens/sec。バッチサイズ 128 は遅延 5s・スループット 256tokens/sec。Dynamic batching で効率化。KV Cache 削減:seq_len=2048, batch=32 で 1GB。対策として Paged attention(vLLM)や FP8 量子化(精度損失 ~1%)。

Few-shot プロンプティング

Zero-shot、One-shot、Few-shot with chain-of-thought。In-context learning により、LLM は示例から学習して新規タスクに対応。

事前学習と微調整

LoRA(Low-Rank Adaptation)

全パラメータ 7B を更新する代わり、低ランク分解 Delta_W ≈ A @ B^T で対応。パラメータ削減:d×d = 7B → 2×d×r = 0.001%。

Prefix tuning

学習可能な埋め込みをプロンプト前缀に付与。パラメータが非常に少ない(prefix_len=20, d_model=4096 → 80k)。

nsformer and inference resources](https://github.c

Attention メカニズム の数学的詳細

Attention は information retrieval の観点で見ると、Query を使用して Key との類似度を計算し、その重み付けで Value を集約。

スケール付きドット積: scores = Q * K^T / sqrt(d_k)。sqrt(d_k) で勾配爆発を防止(特に d_k が大きい場合)。

Multi-Head Attention の利点: 異なる部分空間で注意パターンを学習。例:1 つのヘッドは長距離依存を捉え、別のヘッドは局所パターンに焦点。

Positional Encoding の設計選択

Sinusoidal PE: 周期関数で相対位置を符号化。任意長文に対応(外挿性)。

Learned PE: 絶対位置に対して埋め込みを学習。柔軟だが、学習データより長い文に弱い。

Rotary Position Embedding(RoPE): 複素数回転で相対位置を表現。GPT-Neo で採用。高い外挿性。

Transformer の計算複雑度と最適化

時間複雑度: O(n^2 * d)(n = sequence length, d = embedding dim)。n=2048, d=4096 で QK^T 計算が dominant。

メモリ複雑度: O(n^2)(attention matrix 全体を保持)。Sparse Attention や Linear Attention で O(n) に削減。

層正規化と活性化関数

LayerNorm vs BatchNorm: Transformer では LayerNorm が主流(sample size 1 でも機能)。

ReLU の問題: Dead ReLU(出力が常に 0)。GELU や SwiGLU で改善。

勾配爆発・消失問題

Long-term dependency がある場合、逆伝播で勾配が exponentially 増加/減少。

Residual connections(skip connection)で勾配フロー改善。LayerNorm でスケール制御。勾配クリッピング(max norm)で爆発を抑制。

Beam Search とテキスト生成

Greedy decoding: 毎ステップで最高確度のトークン選択。高速だが質低下。

Beam search: 複数の候補を保持(beam width = 5 等)。スコアでリランク。ビーム幅大で品質向上、遅延増加。

Temperature sampling: softmax 前に温度 T を適用。T > 1 で多様性、T < 1 で確定性。

Transfer Learning と事前学習モデル

事前学習モデルを特定タスクに微調整(fine-tune)。ImageNet で学習した ResNet を医療画像分類に転用。計算コスト・学習時間大幅削減。

BERT、GPT など NLP 事前学習モデルの汎用性。テキスト分類、抽出、生成タスクで高精度。

Multitask Learning: 複数タスクを同時学習。shared representation で汎化性向上。

確率的勾配降下法(SGD)と最適化アルゴリズム

Momentum: 勾配方向の速度を保持。鞍点からの脱出高速化。

Adam: 勾配の一次・二次モーメント推定。自動的な学習率調整。ほとんどの深層学習で採用。

Learning rate schedule: 固定値より動的調整(warmup → decay)。収束安定性向上。

正則化と過学習対策

L1/L2 正則化(weight decay): 重みの大きさを制限。L1 で sparse 解導出。

Dropout: ランダムにニューロンを無効化。co-adaptation 防止。推論時は全ニューロン使用(スケーリング調整)。

Early Stopping: 検証損失が改善しなくなった時点で学習終了。過学習防止。

Batch Normalization: 各層入力の分布を正規化。勾配安定、学習率上昇可能。

不均衡データセット への対応

Class imbalance: 例えば医療診断で病例 1% のみ。単純精度では意味ない。

F1 スコア、ROC AUC で評価。困惑行列(TP、FP、TN、FN)で詳細把握。

Over-sampling(少数クラス複製)と Under-sampling(多数クラス削除)。Synthetic data generation(SMOTE)。

Cost-sensitive learning: 少数クラスの誤分類にペナルティ加重。

詳細な実装例集

ResNet(残差ネットワーク)の構造

Skip connection が信号パスをバイパス。深いネットワークでの勾配消失問題を緩和。

input -> Conv -> BatchNorm -> ReLU -> Conv -> + -> ReLU -> output
                                        ^
                                        |
                        (skip connection from input)

ResNet-50: 50 層。ImageNet で 76% top-1 精度。競争的なタスクで定番。

U-Net(セマンティックセグメンテーション)

エンコーダ-デコーダアーキテクチャ。Low-level 特徴を skip connection で decoder に直接注入。

医療画像(CT、MRI)のセグメンテーションで高精度。少データでも効果的(Data Augmentation + skip connections)。

Attention Is All You Need(元の Transformer 論文)

2017 Vaswani et al. Multi-head self-attention のみで SOTA 達成。RNN/CNN 不要。

Sequence-to-sequence(翻訳など)の新パラダイムシフト。並列化可能で GPU フレンドリー。

Vision Transformer(ViT)

画像を patch に分割して embedding。Transformer を画像認識に適用。

ImageNet で CNN と同等以上の精度(ただし大規模事前学習必要)。

Diffusion Models(拡散モデル)

ノイズ を段階的に追加して逆過程を学習。画像生成(Stable Diffusion、DALL-E 3)で最新 SOTA。

ノイズ除去の反復で高品質生成。確率的生成で多様な出力。

om/NVIDIA/FasterTransformer) - Transformer推論最適化

まとめ

深層学習は、表現そのものを学ぶ多層モデルです。Transformerと大規模事前学習により、その延長線上にLLMが現れました。ニューラルネットの基本、逆伝播、正則化、表現学習TransformerLLMの評価と安全性をつなげて見ると、現在のAIシステムがどこで強く、どこで壊れやすいかが見えやすくなります。

Self-Attentionのメカニズム、Multi-Head Attentionによる多角的な関係学習、Positional Encodingによる順序情報の統合といった個々の要素が、なぜTransformerを強力にしたのか、また実装上の工夫(Residual接続、Layer Norm)が深層化を可能にしたのかを理解することで、LLMの動作原理と限界が明確になります。

参考文献

論文

講義・記事

書籍

解説・補助

Self-Attention メカニズムの計算詳細

Self-attention は Query、Key、Value の 3 つの線形投影から構成される。

計算式(スケール付きドット積注意): Attention(Q,K,V) = softmax(Q*K^T/sqrt(d_k))*V

具体例(日本語文の注意スコア計算)では、トークン “私” は “猫” に最も注意を払う。Multi-Head Attention では 8 ヘッドで異なる部分空間を学習。

Positional Encoding と位置情報

Transformer は RNN の連続処理がないため、位置情報を明示的に付与。Sinusoidal Positional Encoding と相対位置エンコーディング(改善版)が利用される。

フィード・フォワード層(FFN)

Attention の後に 2 層の密集層。Standard FFN では d_ff = 2048(d_model = 512 の 4 倍)。Gated Linear Unit(GLU)変種は GPT-3 で採用。計算量:Self-attention は O(n^2d)、FFN は O(nd_model^2)で、長文処理時は Attention が bottleneck。