第4章:正則化と最適化テクニック

過学習を防ぎ、学習効率を向上させる

📖 読了時間: 30-35分 💻 コード例: 8個 📝 演習: 6問 📊 難易度: 中級
この章では、モデルの汎化性能と学習効率を向上させる技術を学びます。過学習を防ぐ正則化手法、安定した学習のための正規化技術、学習率を自動調整する高度な最適化アルゴリズムをカバーします。

学習目標

1. 過学習(Overfitting)の理解

1.1 訓練誤差と汎化誤差

過学習は、モデルが訓練データをノイズや特殊性を含めて学習しすぎ、新しい未知のデータでの性能が悪くなる現象です。

シナリオ 訓練誤差 検証誤差 状態
過少学習 高い 高い モデルが単純すぎる
良好なフィット 低い 低い 最適
過学習 非常に低い 高い モデルが暗記

1.2 バイアス-バリアンス トレードオフ

バイアス-バリアンスのトレードオフは、モデルの複雑さと誤差の関係を説明します:

$$\text{総誤差} = \text{バイアス}^2 + \text{バリアンス} + \text{既約誤差}$$

2. 正則化手法

2.1 L1正則化(Lasso)

L1正則化は重みの絶対値の和を損失関数に追加します:

$$\mathcal{L}_{L1} = \mathcal{L}_{original} + \lambda \sum_{i} |w_i|$$

特徴

2.2 L2正則化(Ridge / Weight Decay)

L2正則化は重みの二乗和を損失に追加します:

$$\mathcal{L}_{L2} = \mathcal{L}_{original} + \frac{\lambda}{2} \sum_{i} w_i^2$$

特徴

2.3 Dropout

Dropoutは訓練中にニューロンの一部をランダムにゼロに設定し、ネットワークに冗長な表現の学習を強制します。

import numpy as np

class Dropout:
    """Dropoutレイヤーの実装"""

    def __init__(self, drop_rate=0.5):
        self.drop_rate = drop_rate
        self.mask = None
        self.training = True

    def forward(self, X):
        if self.training and self.drop_rate > 0:
            self.mask = np.random.binomial(1, 1 - self.drop_rate, X.shape)
            return X * self.mask / (1 - self.drop_rate)
        return X

    def train(self):
        self.training = True

    def eval(self):
        self.training = False

# 使用例
dropout = Dropout(drop_rate=0.5)
X = np.ones((3, 5))

dropout.train()
output_train = dropout.forward(X)
print("訓練モード出力:\n", output_train)

重要:推論時は必ず評価モードに切り替えてください:

3. Batch Normalization

3.1 内部共変量シフト

内部共変量シフトとは、訓練中に層の入力分布が変化する現象です。Batch Normalizationは層の入力を正規化することでこれに対処します。

3.2 Batch Normの仕組み

ミニバッチの活性化に対して、Batch Normは以下を実行します:

  1. 平均と分散を計算

    $$\mu_B = \frac{1}{m}\sum_{i=1}^{m} x_i, \quad \sigma_B^2 = \frac{1}{m}\sum_{i=1}^{m}(x_i - \mu_B)^2$$

  2. 正規化

    $$\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}$$

  3. スケールとシフト(学習可能パラメータ):

    $$y_i = \gamma \hat{x}_i + \beta$$

3.3 Layer Normalizationとの比較

側面 Batch Normalization Layer Normalization
正規化対象 バッチ次元 特徴次元
バッチサイズ依存 あり(大きなバッチが必要) なし
最適な用途 CNN、フィードフォワード RNN、Transformer

4. 最適化アルゴリズム

4.1 AdaGrad

AdaGradは過去の勾配に基づいて各パラメータの学習率を適応的に調整します。

4.2 RMSprop

RMSpropは指数移動平均を使用してAdaGradの学習率減少問題を解決します。

4.3 Adam / AdamW

Adam(Adaptive Moment Estimation)はモメンタムとRMSpropを組み合わせます:

$$m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t \quad \text{(第1モーメント)}$$

$$v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2 \quad \text{(第2モーメント)}$$

$$\theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t$$

オプティマイザ選択ガイドライン

5. 学習率スケジューリング

5.1 Step Decay

特定のエポックで学習率を係数で減少:

$$\eta_t = \eta_0 \cdot \gamma^{\lfloor t / s \rfloor}$$

5.2 Cosine Annealing

コサインカーブに従って学習率を滑らかに減少:

$$\eta_t = \eta_{min} + \frac{1}{2}(\eta_{max} - \eta_{min})(1 + \cos(\frac{t \pi}{T}))$$

5.3 Warmup

Warmupは訓練開始時に学習率を徐々に増加させます。

6. Early Stopping

早期終了は検証損失を監視し、改善が止まったら訓練を停止して過学習を防ぎます。

class EarlyStopping:
    """過学習を防ぐ早期終了"""

    def __init__(self, patience=10, min_delta=0.0001):
        self.patience = patience
        self.min_delta = min_delta
        self.best_loss = float('inf')
        self.counter = 0

    def __call__(self, val_loss):
        if val_loss < self.best_loss - self.min_delta:
            self.best_loss = val_loss
            self.counter = 0
            return False
        else:
            self.counter += 1
            if self.counter >= self.patience:
                print(f"早期終了: {self.patience}エポック改善なし")
                return True
            return False

演習問題

演習1:L1 vs L2正則化

問題:同じデータでL1とL2正則化を使って訓練し、重み分布とスパース性を比較してください。

演習2:Dropout率の実験

問題:Dropout率[0, 0.1, 0.3, 0.5, 0.7]でネットワークを訓練し、最適な率を見つけてください。

演習3:Batch Normalizationのアブレーション

問題:Batch Normalizationあり/なしで訓練を比較し、損失曲線と学習率への感度を確認してください。

演習4:オプティマイザの比較

問題:SGD、Momentum、RMSprop、Adamで同じネットワークを訓練し、収束曲線を比較してください。

演習5:学習率スケジュールの設計

問題:固定、Step Decay、Cosine Annealing、Warmup+Cosineを実装し比較してください。

演習6:早期終了の分析

問題:patience=5, 10, 20で早期終了を実装し、最終テスト精度を比較してください。

まとめ

この章では、モデル訓練を改善する技術を学びました:

次章の予告:第5章では、学んだすべてを実践プロジェクトに適用します。MNISTの分類、データ前処理パイプライン、モデル評価、ハイパーパラメータチューニングを行います。

免責事項