最適化テクニック
田中VPoE:「正則化で過学習を防ぐ方法を学んだ。次は、学習プロセス自体を最適化するテクニックだ。学習率の動的調整や Mixed Precision など、実務で効果が大きい手法を押さえよう。」
あなた:「学習率を固定するのではなく、学習中に変化させるんですね。」
田中VPoE:「そうだ。最初は大きな学習率で広く探索し、徐々に小さくして精密に収束させる。このテクニック1つで性能が大きく変わることもある。」
学習率スケジューリング
学習率を学習中に動的に変化させることで、収束の速度と精度を改善します。
主要なスケジューラー
| スケジューラー | 挙動 | 用途 |
|---|---|---|
| StepLR | 一定エポックごとに減衰 | シンプルな学習 |
| CosineAnnealingLR | コサインカーブで減衰 | CNN の学習 |
| OneCycleLR | 1サイクルで上昇→減衰 | 高速収束 |
| ReduceLROnPlateau | 検証損失が停滞したら減衰 | 汎用的 |
| Linear with Warmup | 線形 Warmup + 線形減衰 | Transformer Fine-tuning |
import torch.optim as optim
from torch.optim.lr_scheduler import (
StepLR, CosineAnnealingLR, OneCycleLR, ReduceLROnPlateau
)
optimizer = optim.Adam(model.parameters(), lr=1e-3)
# StepLR: 30エポックごとに学習率を0.1倍
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
# CosineAnnealing: 50エポックで最小学習率まで減衰
scheduler = CosineAnnealingLR(optimizer, T_max=50, eta_min=1e-6)
# OneCycleLR: 最大学習率まで上昇→減衰
scheduler = OneCycleLR(
optimizer, max_lr=1e-2,
steps_per_epoch=len(train_loader),
epochs=num_epochs
)
# ReduceLROnPlateau: 検証損失が10エポック改善しなければ0.5倍
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=10)
学習ループでの使用
for epoch in range(num_epochs):
model.train()
for batch_X, batch_y in train_loader:
optimizer.zero_grad()
outputs = model(batch_X)
loss = criterion(outputs, batch_y)
loss.backward()
optimizer.step()
# OneCycleLR はバッチごとに更新
# scheduler.step()
# StepLR, CosineAnnealing はエポックごとに更新
scheduler.step()
# ReduceLROnPlateau は検証損失を渡す
# scheduler.step(val_loss)
print(f"Epoch {epoch+1}: lr={optimizer.param_groups[0]['lr']:.6f}")
Warmup
学習の最初は小さい学習率から始め、徐々に本来の学習率まで上げる手法です。
from transformers import get_linear_schedule_with_warmup
total_steps = len(train_loader) * num_epochs
warmup_steps = int(total_steps * 0.1) # 最初の10%
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=warmup_steps,
num_training_steps=total_steps
)
なぜ Warmup が必要か
Warmup なし:
初期の大きな学習率 → ランダムな重みが大きく更新 → 不安定
Warmup あり:
小さい学習率で開始 → 重みが安定してから本来の学習率に → 安定した学習
Warmup は特に以下の場面で効果的です:
- Transformer の Fine-tuning
- 大きなバッチサイズでの学習
- 複雑なモデルの学習初期
AdamW
Adam の改良版で、Weight Decay を勾配更新から分離して正しく適用します。
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-3,
betas=(0.9, 0.999), # モメンタム係数
eps=1e-8, # ゼロ除算防止
weight_decay=0.01 # 重み減衰
)
| Optimizer | 推奨場面 |
|---|---|
| SGD + Momentum | CNN の長時間学習(最終精度が高い) |
| Adam | 汎用的、素早い収束 |
| AdamW | Transformer、Fine-tuning |
Mixed Precision Training
FP32(32ビット浮動小数点)と FP16(16ビット)を混合して計算することで、メモリ使用量を削減し、学習を高速化します。
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
for batch_X, batch_y in train_loader:
batch_X, batch_y = batch_X.to(device), batch_y.to(device)
optimizer.zero_grad()
# autocast で FP16 計算を自動適用
with autocast():
outputs = model(batch_X)
loss = criterion(outputs, batch_y)
# GradScaler で勾配のスケーリング
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
Mixed Precision の効果
| 項目 | FP32 のみ | Mixed Precision |
|---|---|---|
| メモリ使用量 | 基準 | 約50%削減 |
| 学習速度 | 基準 | 1.5~3倍高速 |
| 精度 | 基準 | ほぼ同等 |
| GPU 要件 | 任意 | Volta 以降(Tensor Core) |
Gradient Clipping
勾配が大きくなりすぎるのを防ぎ、学習を安定化します。
# 勾配のノルムを最大1.0に制限
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 学習ループ内での使用
optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
最適化テクニックの組み合わせ
# 実務的な最適化設定の例
model = MyModel().to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4, weight_decay=0.01)
total_steps = len(train_loader) * num_epochs
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=int(total_steps * 0.1),
num_training_steps=total_steps
)
scaler = GradScaler()
for epoch in range(num_epochs):
model.train()
for batch in train_loader:
optimizer.zero_grad()
with autocast():
loss = compute_loss(model, batch)
scaler.scale(loss).backward()
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer)
scaler.update()
scheduler.step()
まとめ
- 学習率スケジューリングで収束速度と精度を改善する
- Warmup は学習初期の不安定さを解消する
- AdamW は Transformer の Fine-tuning に推奨される Optimizer
- Mixed Precision はメモリ削減と高速化を両立する
- Gradient Clipping は勾配爆発を防ぎ、学習を安定化する
チェックリスト
- 主要な学習率スケジューラーの特徴と使い分けを理解した
- Warmup の必要性と設定方法を理解した
- AdamW と通常の Adam の違いを説明できる
- Mixed Precision Training の概念と効果を理解した
推定読了時間: 30分