「機械学習モデルが賢くなる仕組みって何?」
「勾配降下法とSGDの違いが分からない…」
ニューラルネットワークの学習に欠かせないのが、SGD(確率的勾配降下法)です。
この記事では、機械学習における最も基本的な最適化アルゴリズムであるSGDについて、基礎から実践まで分かりやすく解説していきますね。
SGDの基本概念

SGDって何?
SGD(Stochastic Gradient Descent:確率的勾配降下法)は、機械学習モデルのパラメータ(重みやバイアス)を最適化するアルゴリズムです。
「確率的」という言葉が付いているのは、データをランダムに選んで更新するからなんですね。
損失関数(誤差)を最小化することで、モデルの予測精度を向上させます。
山登りの逆バージョン
SGDは、「山を下る」過程に例えられます。
目的:
谷底(損失が最小の地点)にたどり着くこと
方法:
現在地で最も急な下り坂の方向を見つけて、少しずつ降りていく
勾配:
その「下り坂の方向」を示すのが勾配(gradient)です
霧の中で下山するように、一歩ずつ慎重に進んでいくイメージですね。
なぜSGDが必要なの?
機械学習では、最適な重みを直接計算できない場合がほとんどです。
理由:
- 問題が複雑すぎる
- データ量が膨大
- 解析的な解が存在しない
そこで、試行錯誤しながら少しずつ改善していく方法が必要になるんです。
通常の勾配降下法との違い
バッチ勾配降下法(BGD)
すべてのデータを使って1回更新します。
特徴:
- 全データで誤差を計算
- 更新が正確
- 計算に時間がかかる
- メモリを大量に消費
100万件のデータがあったら、100万件すべてを見てから1回更新しますね。
確率的勾配降下法(SGD)
1つのデータだけで更新します。
特徴:
- 1データごとに誤差を計算して即座に更新
- 更新が頻繁
- 計算が高速
- 経路がジグザグになる
100万件のデータなら、100万回の更新が行われます。
ミニバッチSGD
現代で最も一般的な方法です。
特徴:
- 小さなグループ(例:32件)ごとに更新
- BGDとSGDの良いとこ取り
- 実質的な「SGD」として使われる
100万件のデータを32件ずつ処理して、約31,250回更新しますよ。
SGDのアルゴリズム
基本的な手順
SGDは、シンプルなステップの繰り返しです。
ステップ1:初期化
重みとバイアスをランダムな小さな値で初期化します。
ステップ2:データを選択
訓練データからランダムに1つ(またはミニバッチ)選びます。
ステップ3:順伝播
選んだデータで予測値を計算しますね。
ステップ4:損失計算
予測値と正解の差(損失)を計算します。
ステップ5:勾配計算
逆伝播で各パラメータの勾配を計算します。
ステップ6:パラメータ更新
勾配を使って重みとバイアスを更新するんです。
ステップ7:繰り返し
収束するまで、またはエポック数に達するまで繰り返します。
更新式
パラメータ更新の数式は、とてもシンプルです。
w_new = w_old - η × ∂L/∂w
記号の意味:
- w:重み(パラメータ)
- η(イータ):学習率
- ∂L/∂w:損失関数Lの重みwに関する勾配
「現在の重みから、勾配に学習率を掛けた値を引く」という操作です。
学習率の重要性
学習率って何?
1回の更新でどれだけパラメータを変更するかを決める値です。
山下りの例えでは、「1歩の大きさ」に相当しますね。
学習率が大きすぎる場合
大股で進みすぎて、谷底を飛び越してしまいます。
問題点:
- 振動して収束しない
- 損失が発散する
- 最適解に到達できない
症状:
学習曲線がジグザグに上下します。
学習率が小さすぎる場合
小股で少しずつ進むため、時間がかかります。
問題点:
- 収束が遅い
- 局所最適解に陥りやすい
- 訓練時間が長くなる
症状:
学習曲線がほとんど変化しません。
適切な学習率の選び方
初期値として、以下が一般的です。
推奨値:
- 0.1、0.01、0.001のいずれか
- Adam使用時:0.001(デフォルト)
- SGD使用時:0.01〜0.1
実験的に調整することが多いですね。
ミニバッチサイズの影響

バッチサイズって何?
1回の更新に使用するデータの数です。
一般的な値:
- 32、64、128、256
- 2の累乗が推奨される
GPUのメモリ効率の観点からも重要ですよ。
小さいバッチサイズ(8〜32)
メリット:
- 更新頻度が高い
- 正則化効果がある
- メモリ使用量が少ない
- 汎化性能が良い場合がある
デメリット:
- 勾配の推定が不安定
- GPUを活用しきれない
大きいバッチサイズ(256〜512)
メリット:
- 勾配の推定が安定
- 計算効率が良い
- GPUを最大限活用
デメリット:
- メモリを大量消費
- 汎化性能が低下する場合がある
- シャープな最適解に陥りやすい
バランスが重要ですね。
実装例
NumPyでのシンプル実装
基本的なSGDを実装してみましょう。
import numpy as np
def sgd_update(params, grads, learning_rate=0.01):
"""
SGDによるパラメータ更新
params: パラメータの辞書 {'W1': w1, 'b1': b1, ...}
grads: 勾配の辞書 {'W1': dw1, 'b1': db1, ...}
learning_rate: 学習率
"""
for key in params.keys():
params[key] -= learning_rate * grads[key]
return params
# 使用例
weights = {'W1': np.random.randn(10, 5)}
gradients = {'W1': np.random.randn(10, 5)}
# パラメータ更新
weights = sgd_update(weights, gradients, learning_rate=0.01)
たった3行の核心部分で実装できますね。
PyTorchでの実装
実際のディープラーニングフレームワークでの使い方です。
import torch
import torch.nn as nn
import torch.optim as optim
# モデル定義
model = nn.Sequential(
nn.Linear(784, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
# SGDオプティマイザの作成
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 訓練ループ
for epoch in range(num_epochs):
for batch_x, batch_y in dataloader:
# 勾配をゼロにリセット
optimizer.zero_grad()
# 順伝播
outputs = model(batch_x)
loss = criterion(outputs, batch_y)
# 逆伝播
loss.backward()
# パラメータ更新(SGD)
optimizer.step()
optimizer.step()が、SGD更新を実行しています。
TensorFlow/Kerasでの実装
import tensorflow as tf
from tensorflow import keras
# モデル構築
model = keras.Sequential([
keras.layers.Dense(128, activation='relu', input_shape=(784,)),
keras.layers.Dense(10, activation='softmax')
])
# SGDオプティマイザを指定してコンパイル
model.compile(
optimizer=keras.optimizers.SGD(learning_rate=0.01),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 訓練
model.fit(x_train, y_train, epochs=10, batch_size=32)
フレームワークが内部でSGDを実行してくれますよ。
SGDの改良版
モメンタム(Momentum)
過去の勾配の情報を利用します。
アイデア:
ボールが転がるように、勢いを持って進みます。
式:
v = γ × v - η × ∂L/∂w
w = w + v
- v:速度(velocity)
- γ(ガンマ):モメンタム係数(通常0.9)
局所最適解を抜け出しやすくなりますね。
Nesterov Accelerated Gradient(NAG)
先読みするモメンタムです。
特徴:
- 進む方向を事前に予測
- より効率的な収束
勾配を計算する位置が、通常のモメンタムと異なります。
Adagrad
学習率を自動調整します。
特徴:
- パラメータごとに異なる学習率
- よく更新されるパラメータは学習率を小さく
- あまり更新されないパラメータは学習率を大きく
欠点:
学習率が徐々に小さくなりすぎる問題があります。
RMSprop
Adagradの改良版です。
特徴:
- 学習率の減衰を緩和
- 最近の勾配を重視
ディープラーニングでよく使われますよ。
Adam
最も人気のある最適化アルゴリズムです。
特徴:
- モメンタムとRMSpropの良いとこ取り
- デフォルト設定でも高性能
- ほとんどの問題で良好な結果
デフォルト設定:
- 学習率:0.001
- β1(モメンタム):0.9
- β2(RMSprop):0.999
迷ったらAdamを使うのが無難ですね。
学習率スケジューリング
固定学習率の問題
ずっと同じ学習率だと、最適化が難しい場合があります。
問題:
- 初期:学習率が小さすぎて遅い
- 後期:学習率が大きすぎて振動
ステップ減衰
一定エポックごとに学習率を減らします。
# 10エポックごとに学習率を半分に
if epoch % 10 == 0:
learning_rate *= 0.5
シンプルで効果的な方法です。
指数減衰
エポックに応じて指数関数的に減衰します。
learning_rate = initial_lr * (decay_rate ** epoch)
Cosine Annealing
コサイン関数で滑らかに減衰します。
特徴:
- 滑らかな減衰
- 周期的に学習率を上げることも可能
最近のディープラーニングでよく使われますね。
Learning Rate Warmup
最初に学習率を徐々に上げます。
アイデア:
初期の不安定な時期に、小さな学習率で慎重に進みます。
大きなバッチサイズを使う場合に特に有効ですよ。
収束の判定

いつ学習を止めるべき?
適切なタイミングで訓練を終了することが重要です。
エポック数の固定:
事前に決めた回数だけ訓練します。
簡単ですが、必ずしも最適ではありません。
早期終了(Early Stopping):
検証データでの性能が改善しなくなったら停止します。
過学習を防ぐ効果もありますね。
損失の変化を監視:
連続して一定以下しか改善しなければ停止します。
学習曲線の確認
訓練データと検証データの損失をプロットします。
正常な学習:
- 訓練損失:順調に減少
- 検証損失:訓練損失とほぼ同じ傾向
過学習:
- 訓練損失:減少し続ける
- 検証損失:途中から増加
検証損失が増加し始めたら、学習を止めるタイミングですよ。
ハイパーパラメータの調整
主要なハイパーパラメータ
SGDで調整すべきパラメータです。
学習率(最重要):
- 0.001、0.01、0.1を試す
- ログスケールで探索
バッチサイズ:
- 32、64、128を試す
- GPUメモリと相談
エポック数:
- 早期終了を使えば、多めに設定してOK
モメンタム(使用する場合):
- 0.9が標準的
グリッドサーチ
すべての組み合わせを試します。
learning_rates = [0.001, 0.01, 0.1]
batch_sizes = [32, 64, 128]
for lr in learning_rates:
for bs in batch_sizes:
# 学習と評価
train_and_evaluate(lr, bs)
確実ですが、時間がかかりますね。
ランダムサーチ
ランダムに組み合わせを選んで試します。
グリッドサーチより効率的な場合が多いです。
Bayesian Optimization
過去の結果を元に、次に試すべきパラメータを賢く選択します。
効率的ですが、実装がやや複雑ですよ。
よくある問題と対処法
損失が減少しない
学習が進まない場合の対処です。
原因と対策:
学習率が小さすぎる:
学習率を10倍にしてみます。
初期化が悪い:
重みの初期化方法を変更します。
勾配消失:
活性化関数をReLUに変更、Batch Normalizationを導入しますね。
損失が発散する
数値が無限大になってしまう問題です。
原因と対策:
学習率が大きすぎる:
学習率を1/10にします。
勾配爆発:
勾配クリッピングを導入します。
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
過学習
訓練データでは良いが、新しいデータで性能が低い問題です。
対策:
- データ拡張
- ドロップアウト
- 正則化(L1、L2)
- 早期終了
- より多くの訓練データ
実践的なヒント
学習開始時のチェックリスト
訓練を始める前に確認すべき事項です。
□ データの正規化
入力データを平均0、標準偏差1に正規化します。
□ 適切な損失関数
問題に応じた損失関数を選択しましょう。
□ 適切な評価指標
精度、F1スコア、AUCなど、目的に合った指標を使います。
□ ベースラインの設定
最低限超えるべき性能を決めておきますね。
デバッグのコツ
問題の切り分け方です。
小さなデータセットで過学習させる:
数十件のデータで訓練損失がゼロに近づくか確認します。
これができなければ、モデルに問題があります。
勾配をチェック:
勾配が正常に計算されているか確認しましょう。
学習率を変えてみる:
1桁上下させて、挙動の変化を観察します。
ログと可視化
訓練の進捗を記録・可視化します。
import matplotlib.pyplot as plt
# 損失の記録
train_losses = []
val_losses = []
for epoch in range(num_epochs):
train_loss = train_one_epoch()
val_loss = validate()
train_losses.append(train_loss)
val_losses.append(val_loss)
# プロット
plt.plot(train_losses, label='Train')
plt.plot(val_losses, label='Validation')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()
視覚的に状況を把握できますよ。
まとめ:SGDで機械学習モデルを最適化しよう
SGD(確率的勾配降下法)は、機械学習における最も基本的で重要な最適化アルゴリズムです。
シンプルながら強力で、現代のディープラーニングの基礎となっています。
この記事の重要ポイント:
- SGDはパラメータを少しずつ更新して最適化する
- 学習率は最も重要なハイパーパラメータ
- ミニバッチSGDが実用的で最も一般的
- モメンタムやAdamなどの改良版が効果的
- 学習率スケジューリングで性能向上
- 適切なバッチサイズはGPUと相談
- 学習曲線の可視化で状況把握
- 過学習には早期終了が有効
- ハイパーパラメータ調整が成功の鍵
- デバッグには小さなデータで確認
まずはシンプルなデータセットで、PyTorchやTensorFlowのSGDを試してみましょう。
実際に動かしながら学習率を変えてみることで、SGDの挙動が体感的に理解できますよ。

コメント