ひとことで言うと
Nesterov加速は、モメンタムの移動量で少し先へ進んだ位置を仮に作り、その位置で勾配を評価して更新する方法です。現在位置の勾配だけで進む通常のモメンタムより、進み過ぎへの補正が早く入ります。
坂道を下る車が、いまいる場所だけでなく、惰性で進んだ先の路面を見てハンドルを切るイメージです。先の傾きを使うので、曲がり始めの判断が遅れません。
なぜ必要か
@@ Nesterov加速では、まず勢いによる予測位置を作り、その予測位置の勾配を次の更新に使います。したがって、モメンタムを捨てずに、先回りした勾配で行き過ぎを抑えます。これは学習率やモメンタム係数を別の最適化手法へ置き換える話ではなく、勾配をどこで評価するかの違いです。
| 手法 | 勾配を取る場所 | 補正のタイミング |
|---|---|---|
| 通常のモメンタム | 現在位置 | 勢いを加えた後 |
| Nesterov加速 | 勢いで進んだ先 | 更新前 |
Nesterov加速では、まず勢いによる予測位置を作り、その予測位置の勾配を次の更新に使います。したがって、モメンタムを捨てずに、先回りした勾配で行き過ぎを抑えます。これは学習率やモメンタム係数を別の最適化手法へ置き換える話ではなく、勾配をどこで評価するかの違いです。
仕組み
を時刻 のパラメータ、 を蓄積する速度、 を学習率、 をモメンタム係数、 を損失とします。先読み位置 を作り、そこで勾配を取ります。
速度とパラメータを次のように更新します。
は先読み位置での損失勾配です。実装では、現在のパラメータを直接書き換えず、一時的な先読み値を作って勾配計算後に元の更新を行います。PyTorchのSGDでは momentum が0でないときに nesterov=True を指定する形で、この方式を選べます。係数の定義や初回ステップの扱いは実装の更新則を確認してください。
試験でどう問われるか
| 問われ方 | 正解に寄る条件 | 引っかけ |
|---|---|---|
| 通常のモメンタムとの差 | 勾配を現在位置ではなく、勢いで進んだ先で評価する | 勢いを使わず毎回先読みするだけとする |
| 更新式の穴埋め | を先に作る | と符号を逆にする |
| 実装設定の確認 | momentum を有効にして nesterov=True とする | Nesterovだけを単独で有効化できるとする |
実装で確かめる
1変数の二次関数で、先読み位置の勾配を使う更新をそのまま実装します。 はパラメータ、 なので勾配は です。
import numpy as np
theta, velocity = 4.0, 0.0
eta, mu = 0.1, 0.9
for _ in range(20):
lookahead = theta + mu * velocity
grad = lookahead
velocity = mu * velocity - eta * grad
theta += velocity
print(theta)
このコードを実行すると 0.4904749238276017 と表示されます。grad = theta に変えると、先読みをしない通常のモメンタムとの違いを同じ条件で比較できます。
取り違えやすいもの
| 用語 | 勾配を評価する位置 | 見分けるポイント |
|---|---|---|
| 通常のモメンタム | 現在の | 現在の勾配に過去の速度を組み合わせる |
| Nesterov加速 | 先読みした | 勢いを加えた仮の位置で勾配を取る |
| SGD | 現在の | 速度の蓄積を使わず、勾配だけで更新する |
| Adam系 | 実装ごとの評価位置 | 一次・二次モーメントを使う別系統の更新則 |
想起チェック
Nesterov加速で、通常のモメンタムと最も違う計算箇所はどこか
勾配を現在位置ではなく、モメンタムによる移動を加えた先読み位置で評価する点です。
先読み位置を表す式は何か
です。 はパラメータ、 は速度、 はモメンタム係数です。
PyTorchでNesterovを有効にする前提は何か
SGDの momentum を有効にしたうえで、nesterov=True を指定します。