
SGD・Momentum・RMSprop・Adamを同じ谷で競走させてみた。Adamが一番強いというのは本当か
ニューラルネットワークの学習では「とりあえずAdamを使っておけばいい」という話をよく聞く。実際、多くのフレームワークでもAdamがデフォルトの最適化アルゴリズムになっていることが多い。ただ、SGD・Momentum・RMSprop・Adamがそれぞれ何をしているのか、数式は知っていても、実際の挙動の違いを自分の目で見たことはなかった。
そこで、最適化アルゴリズムの難しさを試すために昔からよく使われるRosenbrock関数という「谷」の上で、この4つを同じ条件で競走させてみた。
Rosenbrock関数という意地悪な谷
この関数は、 に唯一の最小値を持つが、そこに至るまでが細長く湾曲したバナナ型の谷になっている。谷の壁は急峻なのに、谷底に沿った方向の勾配はとても緩やか。「どちらの方向にどれだけ進むべきか」の見積もりを誤りやすい、最適化アルゴリズムの試金石としてよく使われる関数だ。
同じ開始地点 から、学習率などのハイパーパラメータだけをそれぞれの手法に合わせてある程度チューニングしたうえで、800ステップ競走させた。
def grad(x, y):
dx = -2 * (1 - x) - 400 * x * (y - x ** 2)
dy = 200 * (y - x ** 2)
return np.array([dx, dy])
def run_momentum(lr=0.0011, beta=0.9):
p = start.copy(); v = np.zeros(2)
for _ in range(n_steps):
g = grad(*p)
v = beta * v + g # 勾配を「速度」として蓄積する
p = p - lr * v
...
def run_adam(lr=0.05, b1=0.9, b2=0.999, eps=1e-8):
p = start.copy(); m = np.zeros(2); v = np.zeros(2)
for t in range(1, n_steps + 1):
g = grad(*p)
m = b1 * m + (1 - b1) * g # 勾配の移動平均(向き)
v = b2 * v + (1 - b2) * g ** 2 # 勾配2乗の移動平均(大きさ)
p = p - lr * (m / (1 - b1**t)) / (np.sqrt(v / (1 - b2**t)) + eps)
...
結果1: 800ステップ後、どこまで辿り着けたか
start=[-1.5 2.5], target=[1. 1.], steps=800
SGD final=(-0.78,+0.62) dist_to_min=1.8208 final_loss=3.174918 到達せず
Momentum final=(+0.99,+0.97) dist_to_min=0.0314 final_loss=0.000199 701ステップ目に到達
RMSprop final=(+0.66,+0.45) dist_to_min=0.6452 final_loss=0.167762 到達せず
Adam final=(+0.93,+0.87) dist_to_min=0.1484 final_loss=0.004646 到達せず
800ステップという同じ予算の中で、目的地(距離0.05以内)にたどり着けたのはMomentumだけだった。「Adamが一番強い」というよくある印象とは違う結果になったので、経路を3Dで可視化してみた。

灰色のSGDだけが、谷の入口付近でジグザグした短い軌跡のまま止まっているのが一目で分かる。マウスでドラッグして色々な角度から見られるインタラクティブ版も置いておく。
結果2: 等高線の上でのレース
3D曲面だと奥行きで経路が重なって見づらい部分もあるので、真上から見た等高線図の上で、実際に4つの点が動いていく様子をアニメーションにした。

SGD(灰)は、スタート地点のすぐ近くで小刻みに振動し続けるだけで、ほとんど前に進めていない。 谷の壁が急なせいで少し進むたびに勾配の向きが大きく変わり、同じ学習率のままだと壁を挟んで行ったり来たりを繰り返してしまう。壁を乗り越えて壊れないように学習率を小さく抑えた結果、谷底方向への前進もほとんど止まってしまっている。一方Momentum(青)は、序盤にある程度の速度(勢い)を蓄積したあと、その勢いのおかげで谷に沿ってスムーズに滑るように進んでいく。
結果3: 損失の下がり方を数値で比較する
イテレーション SGD Momentum RMSprop Adam
0 156.25 156.25 156.25 156.25
100 4.66 2.60 6.29 4.63
300 3.85 0.020 5.44 0.75
500 3.35 0.0011 3.32 0.081
800 3.17 0.0002 0.168 0.0046

この対数グラフが今回一番面白かった部分だ。SGDは最初のスパイクのあとほぼ横ばいになってしまう。RMSprop(緑)は600ステップ付近まで停滞したあと、階段状にストンと落ちている場面があり、蓄積した勾配2乗の移動平均がある時点で急に効き始めるような、非線形な挙動が見える。Momentum(青)は終始一貫して最も急な傾きを保ち、最終的に他の3つを1〜4桁差で引き離した。
Adamが常に最強、ではなかった
正直、実験前は「Adamが一番速く収束するんだろう」と予想していた。実際には、このRosenbrock谷・この予算(800ステップ)・このハイパーパラメータの組み合わせでは、シンプルなMomentumが一番早く目的地に到達した。調べてみると、これは知られている話で、Adamのような適応的な学習率は「汎用的に扱いやすい」という利点はあるものの、特定の地形やタスクでは、素直なMomentumやSGDの方が最終的な収束の質で上回ることがあるらしい。「Adamにしておけば安心」という判断は、少なくとも万能ではない。
これは物事への取り組み方にも通じる話だと思った。SGDのように、目の前の情報だけを頼りに細かく方向修正を繰り返すやり方は、地形が入り組んでいると同じ場所で足踏みし続けてしまう。逆にMomentumのように、直近の勢い(それまでの積み重ね)を活かして進む方が、多少ノイズがあっても大きな流れに逆らわず前進し続けられる。Adamのように状況に応じて細かく調整する賢さは、多くの場面で便利ではあるものの、それが常に一番良い結果を生むとは限らない。慎重な調整より、勢いに乗って押し切る方が結果的に速いことも、実際にはある。
まとめ
- Rosenbrock関数という「谷底の勾配は緩やか、壁は急峻」な意地悪な地形の上で、SGD・Momentum・RMSprop・Adamを同じ開始地点から800ステップ競走させた
- SGDは壁のあいだで小刻みに振動するだけでほとんど前進できず、800ステップ後も損失3.17と目的地から大きく取り残された
- 一番早く目的地(距離0.05以内)に到達したのはMomentumで、701ステップ目に到達。最終損失も0.0002と他を1〜4桁引き離した
- Adam(0.0046)・RMSprop(0.168)はMomentumほど収束しきらず、「Adamが常に最強」というよくある印象は、少なくともこの実験条件では成り立たなかった
- RMSpropの損失曲線には600ステップ付近で階段状に急落する非線形な挙動が見られ、蓄積された勾配2乗の移動平均がある時点から急に効き始めるような振る舞いが確認できた


