深層学習

確率的勾配降下法

1回の更新に使うサンプル数で、バッチ・確率的・ミニバッチ勾配降下法を切り分ける。勾配推定のノイズ、バッチサイズと学習率、並列化の関係を更新式から整理する。

  • A|中核
  • 深層学習

数式の記号で止まったら 記号の読み方 (∂・⊙・転置・上付き添字を、読み方から)

ひとことで言うと

確率的勾配降下法(SGD)は、全訓練データの勾配を毎回正確に求めず、ランダムに選んだサンプル(またはミニバッチ)から勾配を推定してパラメータを更新する方法です。3者の違いは名前よりも、1回の更新に何サンプル使うかで見ると迷いません。

大きな荷物を運ぶとき、全員の意見を集めてから一歩進むのがバッチ、ひとりの意見だけで小刻みに進むのが確率的勾配降下、数人の意見を平均して進むのがミニバッチです。後ろ2つは一歩ごとの判断に揺れがある代わりに、全員を待つ時間を減らせます。

なぜ必要か

訓練目的がサンプルごとの損失の平均なら、全データ NN 個で勾配を計算するバッチ法は正確です。しかし全データを評価するため重くなります。ランダムに mm 個だけ選べば、計算量を抑えられます。

サンプル数を増やしても勾配推定の標準誤差はおおむね 1/m1/\sqrt{m} でしか減りません。この逓減がミニバッチを置く理由です。

全データを使う方法では、データを1例追加しても、その例を含む勾配を計算し終えるまで更新を開始できません。データセットが大きいほど、各更新の待ち時間とメモリへの負担が積み上がり、同じデータを何度も学習する過程でも毎回全件を読み直すことになります。逆に1例だけで更新すると、1回の計算は軽くても例ごとのばらつきがそのまま更新方向に現れます。SGDはこの正確さと更新の速さの交換条件を受け入れ、全体の傾向を完全に知る前に次の更新へ進める点に意味があります。

方法1回の更新に使うサンプル勾配の性質
バッチ勾配降下法全訓練データ NN正確な訓練集合勾配
確率的勾配降下法1分散が大きい推定
ミニバッチ法1<m<N1<m<N分散と計算量の折衷

仕組み

訓練例を (x(i),y(i))(x^{(i)},y^{(i)})、モデルのパラメータを θ\theta、1例の損失を Li(θ)L_i(\theta)、ミニバッチのサンプル数を mm とします。ミニバッチ BkB_k をランダムに選んだとき、平均勾配の推定値は次です。

g^k=1m∑i∈Bk∇θLi(θk)\hat{g}_k=\frac{1}{m}\sum_{i\in B_k}\nabla_\theta L_i(\theta_k)

∇θLi\nabla_\theta L_i は例 ii の勾配、θk\theta_k は更新 kk 回目のパラメータ、BkB_k は選んだ集合です。更新式は

θk+1=θk−εkg^k\theta_{k+1}=\theta_k-\varepsilon_k\hat{g}_k

となります。εk\varepsilon_k は学習率です。m=1m=1 なら確率的、m=Nm=N ならバッチ、途中の mm ならミニバッチです。文献によって「SGD」をミニバッチを含む総称として使います。

ここで g^k\hat{g}_k は損失そのものではなく、現在の θk\theta_k で評価した損失を下げる向きのベクトルです。各例の勾配を足してから mm で割るため、例数を変えても勾配の尺度を平均損失に対応させられます。したがって、和のまま使う式と平均を使う式では、同じ更新幅にするための学習率の解釈が変わります。更新式のマイナスは、勾配が増加方向を示すので、その反対へ進むことを表します。

小さい mm の勾配にはサンプリング由来のノイズが残ります。局所的な領域から動く方向や、過度な適合を抑える効果を持ちます。ただし分散が大きいほど不安定です。

このノイズは、各ミニバッチの推定値が全訓練集合の勾配と一致しないことから生じます。そのため損失が毎回単調に下がるとは限らず、更新の軌跡はバッチ法より揺れます。一方、同じデータだけで決まる方向に固定されにくいので、ノイズを単純な計算誤差として消すのではなく、学習率とバッチサイズを含めた更新の性質として扱います。

学習率を固定したままにできるバッチ法と違い、SGDでは推定ノイズが極小点に近づいても消えません。そのため学習率を徐々に下げます。理論上の十分条件の一つは、εk\varepsilon_k が次を満たすことです。

∑k=1∞εk=∞,∑k=1∞εk2<∞\sum_{k=1}^{\infty}\varepsilon_k=\infty,\qquad \sum_{k=1}^{\infty}\varepsilon_k^2<\infty

前者は早く止まらない条件、後者はノイズの累積を抑える条件です。実務上は学習率を線形に減衰させます。初期値が大きすぎれば振動し、小さすぎれば進みが遅くなります。

この2条件は、学習率を「小さければ小さいほどよい」と読むためのものではありません。総和が発散する条件があるため、学習率を急に小さくしてしまうと、十分に更新する前に動きが止まります。反対に二乗和が収束しない設定では、ノイズによる揺れを長く残します。試験では、単なる学習率の大小ではなく、通常の総和と二乗和を分けて確認します。

ミニバッチ内の例は並列処理できますが、極端に小さいと演算資源を使い切れず、大きくするとメモリを消費します。バッチサイズは勾配の分散、メモリ容量、ハードウェア、1更新の時間の交点で決まります。

試験でどう問われるか

問われ方正解に寄る条件引っかけ
3手法の比較1更新に使うサンプル数を、全件・1件・その中間で区別する「ミニバッチは全データを使う」とする
更新式の記号g^k\hat g_k は選んだ mm 例の勾配平均、εk\varepsilon_k は学習率勾配の符号を逆にして損失増加方向へ進める
バッチサイズを増やす効果勾配推定は正確になるが、標準誤差の改善は 1/m1/\sqrt m で逓減する計算量も同じ比率で効率化すると考える
ノイズと学習率小バッチほど揺れが大きく、安定性のため学習率を下げる場合があるノイズは常に悪影響とする
収束条件学習率の総和は発散し、二乗和は収束する学習率を単に一定にすれば十分とする
並列化ミニバッチ内の例を並列処理でき、メモリはバッチサイズに伴って増える大きくすれば無条件に速くなるとする

引っかけは、サンプル数を増やすと推定が良くなるという一面だけを取り出し、更新回数や計算資源の制約を消してしまう形になりやすいです。バッチサイズの比較では、勾配の分散だけでなく、1回の更新で待つ計算量とメモリも同時に見ます。また「SGD」という略称だけで m=1m=1 と決めつけると、文献での広義の用法と衝突します。式に mm が現れている場合は、まずその範囲を読み取るのが安全です。

実装で確かめる

batch_size を変えると、1回の更新で参照する例数と更新回数が変わります。

import numpy as np

rng = np.random.default_rng(0)
x = rng.normal(size=(10, 2))
y = 2 * x[:, 0] - x[:, 1]

for batch_size in (10, 1, 4):
    theta = np.zeros(2)
    updates = 0
    for start in range(0, len(x), batch_size):
        xb, yb = x[start:start + batch_size], y[start:start + batch_size]
        error = xb @ theta - yb
        grad = 2 * xb.T @ error / len(xb)
        theta -= 0.1 * grad
        updates += 1
    print(batch_size, updates)

取り違えやすいもの

用語切り分け
バッチ勾配降下法全訓練データの勾配を使う決定論的な方法。更新ごとのサンプリングノイズはない
確率的勾配降下法1例だけを使う狭義の意味と、ミニバッチを含む広義の意味がある。文脈ではサンプル数を確認する
ミニバッチ勾配降下法1例より多く全件より少ない集合の平均勾配を使う。深層学習で一般的な折衷
モメンタム過去の勾配も使う拡張。バッチサイズを決める手法ではない
適応的最適化パラメータごとに学習率を調整する別系統の手法。ここでは更新式の基本形までに留めます

モメンタムや適応的最適化は、ミニバッチから得た勾配をどう使うかを拡張します。したがって、これらを加えても「何例から勾配を推定したか」というバッチサイズの分類は変わりません。逆に、バッチサイズを変えただけでは過去の更新を記憶したことにも、パラメータごとに学習率を変えたことにもなりません。勾配の作り方と、作った勾配の更新方法を分けて読むと境界を保てます。

想起チェック

バッチ、確率的、ミニバッチの違いを何で分類するか

1回の更新に使うサンプル数です。全件ならバッチ、1件ならSGD、その中間ならミニバッチです。

ミニバッチの勾配推定値は何を平均しているか

選んだ集合 BkB_k の各例の勾配を足し、サンプル数 mm で割っています。

SGDで学習率を減衰させる理由は何か

サンプリングによる勾配のノイズが、極小点に近づいても消えないからです。学習率を下げて更新の揺れを小さくします。

出典