概要
個人的な備忘録を兼ねたPyTorchの基本的な解説とまとめになります。損失関数の値を小さくするようにパラメータを更新するときに利用する方法、これがオプティマイザーなのですが、AdamやAdamWを選択しておけば大丈夫だろうという状態でした![]()
考え方や細かいパラメータなどを知るために、今一度オプティマイザーについて簡単にまとめてみました。
登場するオプティマイザー
$\theta$を更新するパラメータ、$L(\theta)$を損失関数とします。ニューラルネットワークでは損失関数 $L(\theta)$ を最小にするパラメータ $\theta$ を探すことが目的となります。
$$
\theta^{*} \in \arg\min_{\theta} L(\theta)
$$
$L(\theta)$は非凸関数でとても複雑なので、$\frac{\partial L}{\partial \theta}=0$を明示的に解くことは極めて困難となります。そこで実際のアルゴリズムは、勾配ベクトル$\frac{\partial L}{\partial \theta}$の値を手がかりに $\theta$ を少しずつ動かし、勾配がほぼ 0 になる点(停留点)を探すことになります。見つけられた値が大域的最小点 $\theta^{*}$ であることが保証されないのが難点ではありますが![]()
以下で紹介するオプティマイザーは、この「少しずつ動かす」部分の工夫の進化と見ることができます。
共通の記号
- $\varepsilon>0$:極小の正数、分母ゼロ化を防ぐために導入
- $\eta > 0$:学習率
- $\theta_t = (\theta_{t,1},...,\theta_{t,j},...,\theta_{t,n})$:$t$ 期のパラメータ
- $g_t = \nabla L_t(\theta_{t-1})$:この記号はラフに使っています。$t-1$期のパラメータ$\theta_{t-1}$で計算した$t$期の損失関数$L_t(\theta_{t-1})$の勾配ベクトル1
パラメータ更新
- $t$ 期のデータと$t-1$ 期のパラメータ$\theta_{t-1}$を使い、$t$ 期の損失 $L_{t}(\theta_{t-1})$を計算
- オプティマイザーに従い、パラメータを$\theta_{t-1}$から$\theta_{t}$へ更新
1. SGD (Stochastic Gradient Descent・確率的勾配降下法)
すべてのデータを使い次の式で$\theta_t$を更新していくのが、勾配降下法 (GD) となります。
$$
\theta_{t} = \theta_{t-1} - \eta g_{t}
$$
データサイズが巨大な場合、すべてデータ(全バッチサイズ)を使うのは現実的ではありません。データの一部を抽出(ミニバッチ化)して勾配降下法を使う形になり、確率的勾配降下法と呼ばれます。おそらく、あまり区別なくSGDと呼ばれているようです。
- 全データを使う場合がGD (勾配降下法)
- ミニバッチにしたものがSGD (確率的勾配降下法)
PyTorchでの使い方
# theta=model.parameters(), lr = 0.001みたいに書く
optimizer = torch.optim.SGD(params=theta, lr=eta)
2. Momentum
SGDに過去の勾配も加えてパラメータを更新する方法となります。次のことが期待されます。
- 一貫した方向成分は強化
- 頻繁に変わる成分は抑制
- 振動を抑えて継続する方向へ進む
過去の勾配情報(勾配の和)を考慮したSGDとすれば良いので、更新式は
\begin{align*}
m_{t} & = \beta m_{t-1} + g_{t}\\
\theta_{t} &= \theta_{t-1} - \eta m_{t}
\end{align*}
となります。初期値を$m_0=0$、$m_{t}$はモメンタムバッファー、$\beta$をモメンタム係数などと呼ばれることがあります。
$m_t$の漸化式を変形してみます。$m_0=0$を利用して$m_{t-1}$ 部分に式を逐次代入するだけです。
\begin{align*}
m_{t}
& = \beta m_{t-1} + g_{t} \\
& = \beta (\beta m_{t-2} + g_{t-1}) + g_{t} \\
& = \beta ^2 m_{t-2} + \beta g_{t-1} + g_{t} \\
& \vdots \\
& = \beta^t m_0 + \beta^{t-1} g_{1} + \beta^{t-2} g_{2} + \cdots + \beta^2 g_{t-2} + \beta g_{t-1} + g_{t} \\
& = \sum_{\tau=1}^{t} \beta^{t-\tau} g_{\tau}
\end{align*}
を得ます。
$g_t$ は$t$ 期の勾配だったので、$m_t$は初期の勾配からの蓄積となります。初期(古い)勾配ほど値が$\beta$で大きく割り引かれることになります。
PyTorchでの使い方
# theta=model.parameters(), lr = 0.001, momentum=0.9みたいに書く
optimizer = torch.optim.SGD(params=theta, lr=eta, momentum=beta)
PyTorchでは、モメンタム計算部分に指数移動平均 (μ=β) の概念を追加した
$$
m_{t} = \beta m_{t-1} + (1-\mu) g_{t}
$$
で計算されていて、dampeningのオプションでμの値も調整できます2。
3. Nesterov Momentum (ネステロフ モメンタム)
Momentumは一貫した方向成分に対して勢いが付きすぎる傾向があるようです。そこで、Momentumで更新されるであろう勾配を考慮した上で、パラメータ更新してみようというアイディアがNesterov Momentumとなります。
Momentumで素直に更新すると、
\begin{align*}
\theta_{t}
& = \theta_{t-1} - \eta m_t \\
& = \theta_{t-1} - \eta (\beta m_{t-1} + g_t) \\
& = \theta_{t-1} - \eta\beta m_{t-1} - \eta g_t
\end{align*}
となります。$-\eta g_t$が勾配降下法の基本部分なので、momentumだけで更新されるパラメータは$\theta_{t-1}-\eta\beta m_{t-1}$の部分と解釈できそうです。
\tilde{\theta}_t = \theta_{t-1} - \eta\beta m_{t-1}
を先読み位置 (lookahead position) と呼んでおきます。先読みしたパラメータの勾配情報(先読み位置)を利用してmomentum更新するのが Nesterov Momentumとなります。式で表現すると次のような形になります。
\begin{align*}
m_t
& = \beta m_{t-1} + \nabla L_t(\tilde{\theta}_t) \\
\theta_{t}
& = \theta_{t-1} - \eta m_t \\
\end{align*}
先読み位置のパラメータ$\tilde{\theta}_{t}$を使い、$t$期の損失$L_t(\tilde{\theta}_t)$を計算する部分がポイントです。
PyTorchでの使い方
SDGの変形なのでPyTorchではSDGのオプションで対応できます3。
torch.optim.SGD(
model.parameters(), # 更新するパラメータtheta
lr = 0.001, # 学習率 eta
momentum = 0.9, # momentum 更新のオプション beta
dampening= 0, # 0以外だとエラー? defalul: 0
nesterov = True, # Nesterov Momentum使う場合のオプション
)
4. Ada Grad (Adaptive Gradient)
パラメータごとに学習率を変えるという大きな転換がおこります。SGD系統はすべてのパラメータ$\theta_t = (\theta_{t,1},...,\theta_{t,n})$を共通の学習率$\eta$で更新する形でした。パラメータ毎に学習率を変えてしまおうという流れがAdaptive〜タイプになります。
Adaptive Gradientは勾配成分大きさ(成分の2乗)を学習率に関連づけた更新方法となります。$t-1$ 期のパラメータ$\theta_{t-1}$の第$j\in\{1,...,n\}$ 成分を$\theta_{t-1,j}$とします。$g_{t,j}$を勾配ベクトルの第$j$成分
$$
g_{t,j}=\frac{\partial L_t}{\partial \theta_{t-1,j}}(\theta_{t-1})
$$
とします。$g_t = (g_{t,1},...,g_{t,j},...,g_{t,n})$ということになります。勾配成分の2乗の和を$G_{t,j}$とおき、初期値を$G_{0,j}=0$とすると、
$$
G_{t,j} = \sum_{\tau=1}^{t} g_{\tau, j}^2
$$
のように定義されます。漸化式で表現するなら、$t-1$ 期までの情報に$t$ 期の情報を加えるという形
$$
G_{t,j} = G_{t-1,j} + g_{t,j}^2
$$
になります。$G_{t,j}$に依存する形で学習率$\eta$の値を調整することで、パラメータ毎に学習率を修正していきます。具体的には、Ada Gradでは次のような更新方法を用いて、大きな勾配を抑制し暴走しにくい挙動へと導きます4。
$$
\theta_{t, j}=\theta_{t-1,j}-\frac{\eta}{\sqrt{G_{t,j}}+\varepsilon}g_{t,j}
$$
- 過去に大きな勾配がある方向の学習率は小さく更新
- 過去に大きな勾配がない方向の学習率は大きく更新
勾配成分をまとめて記述すると次の形になります。
\begin{align*}
G_t
& = G_{t-1} + g_ t \odot g_t \\
\theta_{t}
&= \theta_{t-1} - \frac{\eta}{\sqrt{G_t}+\varepsilon}g_t
\end{align*}
$g_t\odot g_t$の$\odot$は要素毎の掛け算で
$$
g_t \odot g_t = (g_{t,1}^2,...,g_{t,n}^2)
$$
という意味になります。
PyTorchでの使い方
# theta=model.parameters(), lr = 0.001, みたいに書く
optimizer = torch.optim.Adagrad(params=theta, lr=eta)
5. RMSProp (Root Mean Square Propagation)
Ada Grad の過去の情報をすべて同一扱いする部分を割り引く形で修正した方式がRMSPropとなります。二乗勾配の指数移動平均$v_t$を使い学習率をコントロールするのがRMSPropとなります。具体的にはAda Gradの$G_{t,j}$の式を
$$
v_{t,j} = \beta v_{t-1,j} + (1-\beta) g_{t,j}^2
$$
と変形させることになります。
初期値を$v_{0}=0$として、逐次的に代入していくと、
\begin{align*}
v_{t,j}
&= \beta v_{t-1,j} + (1-\beta) g_{t,j}^2 \\
& = \beta \Bigl(\beta v_{t-2,j}+ + (1-\beta) g_{t-1,j}^2\Bigr) + + (1-\beta) g_{t,j}^2 \\
& = \beta^2 v_{t-2,j} + (1-\beta) \beta g_{t-1,j}^2 + (1-\beta) g_{t,j}^2 \\
& \vdots \\
& = \beta^t v_{0,j} + (1-\beta) \beta^{t-1,j} g_{1,j}^2+ \cdots+(1-\beta) \beta g_{t-1,j}^2 + (1-\beta) g_{t,j}^2 \\
& = (1-\beta)\sum_{\tau=1}^{t}\beta^{t-\tau}g_{t,j}^2
\end{align*}
となります。指数移動平均を用いて過去の勾配を活用する形になります。勾配成分毎でをまとめて記述すると更新式は次の形になります。
\begin{align*}
v_t
& = \beta v_{t-1} + (1-\beta) g_ t \odot g_t \\
\theta_{t}
&= \theta_{t-1} - \frac{\eta}{\sqrt{v_t}+\varepsilon}g_t
\end{align*}
PyTorchでの使い方
optimizer = torch.optim.RMSprop(
params=theta,
lr=eta,
alpha=beta, # pytorchのオプション名は alpha なので注意
)
6. Adam (Adaptive Moment Estimation)
Adamは過去の勾配履歴の平均と勾配スケールの平均を用いて
$$
\eta \cdot 更新の方向 = \eta \cdot \frac{勾配の平均}{\sqrt{勾配の2乗平均}}
$$
という具合にパラメータを更新する方法となります。勾配平均がMomentum、$\eta$と分母の勾配2乗平均部分がRMSPropの発想となります。基本的な式は4種類になります。
更新式
(1) 1次モーメント (勾配の指数移動平均・$E[g_t]\approx m_t$)
$$
m_t = \beta_1 m_{t-1} + (1-\beta_1)g_t
$$
(2) 2次モーメント(勾配2乗の指数移動平均・$E[g_t^2]\approx v_t$)
$$
v_t = \beta_2 v_{t-1} + (1-\beta_2)g_t^2
$$
(3) バイアス補正
\begin{align*}
\hat{m}_t & = \frac{m_t}{1-\beta_1^t}\\
\hat{v}_t & = \frac{v_t}{1-\beta_2^t}
\end{align*}
(4) 更新方法
$$
\theta_{t} = \theta_{t-1} - \eta
\frac{\hat{m_t}}{\sqrt{\hat{v}_t}+\varepsilon}
$$
手短な解説
1次モーメント
$m_0=0$として、$m_{t-1}$部分に順番に代入していくと、
$$
m_t = (1-\beta_1)\sum_{\tau=1}^{t}\beta_1^{t-\tau}g_{\tau}
$$
という形になります。過去の勾配を指数移動平均したものになります。
2次モーメント
$v_0=0$として、$v_{t-1}$部分に順番に代入していくと、
$$
v_t = (1-\beta_2)\sum_{\tau=1}^{t}\beta_2^{t-\tau}g_{\tau}^2
$$
という形になります。過去の勾配の大きさ(2乗)を指数移動平均したものになります。
バイアス補正
初期値$m_0=0$と$v_0=0$によるモーメント推定の偏りを補正して、初期更新の更新スケールを正しくする調整となります。1次モーメントだけに絞って効果を確認してみました。
1次モーメントを $t=1$ で書き表すと、
$$
m_1 = \beta_1 m_{0} + (1-\beta_1)g_1
$$
初期値を $m_0=0$ とすると、
$$
m_1 = (1-\beta_1)g_1
$$
バイアス補正した $\hat{m}_1$ を使わずに $m_1$ のままmomentumっぽい変数更新を行うと、
\begin{align*}
\theta_2
& = \theta_1 - \eta m_1 \\
& = \theta_1 - \eta (1-\beta_1)g_1
\end{align*}
1期の勾配 $g_1$ が$(1-\beta_1)$だけ過小評価されていることがわかります。補正された $\hat{m}_1$を用いると、
\begin{align*}
\theta_2
& = \theta_1 - \eta \hat{m}_1 \\
& = \theta_1 - \eta \frac{m_1}{1-\beta_1}\\
& = \theta_1 - \eta g_1
\end{align*}
となり、きれいにmomentum更新の形と一致します。
補正した $\hat{m}_t$ と $\hat{v}_t$ を使うことで、初期時点の更新スケールを適正化していることがわかります。
ちなみに、$\hat{m}_t = m_t/(1-\beta_1^t)$なので、十分 $t$ が大きいと$\hat{m}_t$と$m_t$の値は近づいてきます。
更新方法
補正された$m_t$と$v_t$を使い、MomentumとRMSPropを合わせた形でパラメータを更新させます。
$$
\theta_{t} = \theta_{t-1} - \eta
\frac{\hat{m_t}}{\sqrt{\hat{v}_t}+\varepsilon}
$$
- $\hat{m}_t$:更新の方向を決定
- $\eta/(\sqrt{\hat{v}_t}+\varepsilon)$:パラメータ毎の学習率を調整
PyTorchでの使い方
optimizer = torch.optim.adam.Adam(
params=theta,
lr=eta,
betas=(beta_1, beta_2) # default: (0.9, 0.999)
)
これまで反射的にAdamだったのですが
ほんの少し詳しくなりました。
7. AdamW
Weight Decay付きAdamに入ります。その前に準備としてL2正則化とWeight Decayの2つを確認しておきましょう。
準備(L2正則化と重み減衰)
L2正則化
損失関数にパラメータが大きいほど損失が増加する項を追加します。
$$
L_{t}^{reg}(\theta_{t-1}) := L_{t}(\theta_{t-1}) + \frac{\lambda}{2}||\theta_{t-1}||^2
$$
正則化損失関数を最小にするようにパラメータを見つけていくのがL2正則化となります。
重み減衰 (weight decay)
大雑把捉えると、weight decayは、「更新時に学習の更新とは別にパラメータの大きさを減少させる項を追加している方法」と言えます。SGDにweight decayを追加した形だと、
\begin{align*}
\theta_{t}
& = \Bigl[\theta_{t-1} - \eta g_t \Bigr]- \eta\lambda\theta_{t-1} \\
& = ( 1- \eta\lambda) \theta_{t-1}- \eta g_t
\end{align*}
と書かれることが多いようです。$\theta_{t-1}$を$(1-\eta\lambda)\theta_{t-1}$へ縮小させる動きとなります。
ややこしいのは、SGDではL2正則化と weight decay (重み減衰)2つが同一視できる点です。
正則化損失関数$L_{t}^{reg}$の勾配を計算($\theta_{t-1}$で微分するだけ)すると、
$$
g_t^{reg} = g_t + \lambda \theta_{t-1}
$$
となります。この勾配$g_t^{reg}$を利用してSGD更新していきます。
\begin{align*}
\theta_{t}
& = \theta_{t-1} - \eta g_t^{reg} \\
& = \theta_{t-1} - \eta (g_t + \lambda \theta_{t-1}) \\
& = \Bigl[\theta_{t-1} - \eta g_t \Bigr]- \eta\lambda\theta_{t-1} \\
& = \text{SGDでの更新} - \text{重み減衰}
\end{align*}
パラメータ更新時に $\eta\lambda\theta_{t-1}$ 引くこととL2正則化で更新することがSGDでは等しくなります。重み減衰に正則化と同等の効果があると期待できます。
Adamに重み減衰を追加してAdamWへ
重み減衰による正則化効果をAdamでも意図した形で使いたいという発想でAdamでのパラメータ更新時に、 $\eta\lambda\theta_{t-1}$ を引き算する形で重み減衰を導入する方法がAdamWとなります。
Adamの適応的な更新は次のような形でした。
\theta_{t} = \theta_{t-1} - \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+\varepsilon}
Adamの適応的な重み更新と独立して、重み減衰効果を導入すると、
\theta_{t} = \theta_{t-1} - \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+\varepsilon} - \eta\lambda\theta_{t-1}
weight decayは、L2正則化同様、大きな重みを抑制する効果を持ちます。$\theta_t$を0へ縮める作用があります。一方、損失最小化を目指す項
$$- \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t}+\varepsilon}$$
によって$\theta_t$は更新されていきます。更新式をまとめると、次のようになります。
-
1次モーメント (勾配の指数移動平均・$E[g_t]\approx m_t$)
$$
m_t = \beta_1 m_{t-1} + (1-\beta_1)g_t
$$ -
2次モーメント(勾配2乗の指数移動平均・$E[g_t^2]\approx v_t$)
$$
v_t = \beta_2 v_{t-1} + (1-\beta_2)g_t^2
$$ -
バイアス補正
$$
\hat{m}_t = \frac{m_t}{1-\beta_1^t},~~~
\hat{v}_t = \frac{v_t}{1-\beta_2^t}
$$ -
更新方法
\theta_{t} = \theta_{t-1} - \eta
\frac{\hat{m_t}}{\sqrt{\hat{v}_t}+\varepsilon} - \eta\lambda \theta_{t-1}
最後に、Adam+L2正則化でも良さそうです。しかし、式を展開していくと、適応的更新部分に影響されるため、意図した正則化が行われないという問題が起こります5。
SDGではL2正則化とWeight Decayが同一視できのですが、Adamでは異なることになります(Loshchilov and Hutter(2019))。
PyTorchでの使い方
optimizer = torch.optim.AdamW(
params=theta,
lr=eta,
betas=(beta_1, beta_2), # default: (0.9, 0.999)
weight_decay=lambda # default: 0.01、lambdaは説明の数式と対応している
)
8. Muon
MomentUm Orthogonalized by Newton-Schulz からの省略語のようです。こんなに自由に省略していいの?読みは「無音」ではなくて、綴的に素粒子で登場する「ミューオン」に寄せているのかな?
AdamWまではパラメータを長いベクトルとして考えていました。Muonでは、2次元の重み(パラメータ)は2次元のまま更新するという発想をします。例えば、biasを考慮しないLinear層は$W$行列を重みとすると、
y = x W^T,~~~
W = \begin{pmatrix}
w_{11} & \dots & w_{1n} \\
\vdots & \ddots & \vdots \\
w_{m1} & \dots & w_{mn}
\end{pmatrix}
として記述されます。この行列の形状をそのまま使い勾配行列
G = \nabla_W L(W) = \begin{pmatrix}
\frac{\partial L}{\partial w_{11}} & \dots & \frac{\partial L}{\partial w_{1n}} \\[6pt]
\vdots & \ddots & \vdots \\[6pt]
\frac{\partial L}{\partial w_{m1}} & \dots & \frac{\partial L}{\partial w_{mn}}
\end{pmatrix}
として、パラメータ$W$を更新していくのがMuonとなります。ベクトルのパラメータには使えず、Adamなどを併用する形となります。
更新式をまとめると、次のようになります。
勾配行列(各層毎に考えます6)
$$
G_t = \nabla_{\theta}L_t(\theta_{t-1})
$$
- 行列版の1次モーメント
$$
B_t = \beta B_{t-1} + G_t
$$ - Newton-Schulz (ニュートン・シュルツ直交化計算)
$$
O_t = NS(B_t)
$$ - 更新方法
\theta_{t} = \theta_{t-1} - \eta O_t
Newton-Schulzの計算部分ですがPyTorchのオプションを見ると(a, b, c)と3つ指定されています。$O_t = NS(B_t)$は
$$
X_0 = \frac{B_t}{||B_t||_F}
$$
として正規化してから反復を始めます7。
$$X_{k+1} = aX_k + b,(X_kX_k^\top)X_k + c,(X_kX_k^\top)^2X_k,\qquad O_t = X_5$$
と逐次計算しているようです8。5回くらい計算した値が$O_t$となります。
PyTorchでの使い方
torch.optim.MuonはPyTorchのバージョンが2.9.1以上で対応しているようです。ニュートン・シュルツの反復計算部分を自作しなくて良いので気軽に使えそうです。Nesterov、重み減衰などの追加指定も可能です。
# Muon only supports 2D params; use a standard optimizer
# such as AdamW for biases, embeddings, and other non-2D
# parameters.
muon_params = [p for p in model.parameters() if p.ndim == 2] # 2D params
other_params = [p for p in model.parameters() if p.ndim != 2] # other params
# Muon使うパターン
optim_muon = torch.optim.Muon(
params=muon_params,
lr=eta,
momentum=beta
)
# 2D以外のパラメータは他のoptimizerを使う
optim_adamw = torch.optim.Adam(other_params, lr=3e-4)
注意
- 2Dパラメータ以外(例えば、bias項)を含むパラメータ更新を実行しようとするとエラーになります。
- LLMの文脈で使う場合、embedding層は2Dパラメータから除くほうがいいらしい。
- 上記のコードだと、embeddingも muon_paramsになってしまうので注意。ネットワーク名を頼りにリストを作るなどの工夫が必要となります。
目次
論文
少しだけアカデミックな世界にも触れてみました![]()
網羅的ではありませんし、源流は他の論文だよ〜という可能性もあります。調べが適当で申し訳ない限りです![]()
SGD
次の2つがSGDの源流?ただ勾配降下法というより全く違う文脈で、確率的に近似するという理解でいいのかな?5ページ前後の短い内容でした。確率的な近似という観点だと更に遡れそうです。
- Robbins & Monro (1951) "A Stochastic Approximation Method"
- Kiefer & Wolfowitz (1952) "Stochastic Estimation of the Maximum of a Regression Function"
Momentum
ニューラルネットワークの文脈だとやはり Hinton氏のようです。異なる分野だともっと古くからありそう。明確にmomentum項を追加しています。
- Rumelhart, Hinton & Williams (1986) "Learning representations by back-propagating errors"
Nesterov Momentum
Nesterovの論文には「ヒルベルト空間における凸計画問題を解く方法を提案した」とあります。別の内容なの?というか全く異なるようにしか思えない。
しかし、謎 🤔 Nesterovの論文が、Hinton氏の論文で引用されていて、しかも"which are inspired by various theoretical convergence-rate theorems (Nesterov,1983)"と書かれている。セクションにも"Momentum and Nesterov’s Accelerated Gradient"というのがあるくらい。ちなみに後者の内容は教科書的な表記になっていました。もう少し丁寧に読めば両論文の関係がわかるのかな![]()
-
Nesterov (1983) "A method of solving a convex programming problem with convergence rate $O(1/k^2)$"
-
Sutskever, Martens, Dahl & Hinton (2013) "On the importance of initialization and momentum in deep learning"
PyTorchでの実装はどうも別の論文を参考にしているみたいだった。こちらは未確認![]()
Ada Grad
COLT (Conference on Learning Theory) 2010で報告された論文が上記で説明したような内容。しかし、2011年版 (Journal of Machine Learning Research版) は同じ名称なのに、別物のように感じる進化😆
- Duchi, Hazan and Singer (2010/2011) "Adaptive Subgradient Methods for Online Learning and Stochastic Optimization"
RMSProp
PMSPropについては探したのですが、論文は上手く見つけられませんでした。講義スライドが示されるばかり。YouTubeの動画で講義内容が視聴できる。
- Hinton (2013) Lecture 6.e "RMSProp: Divide the gradient by a running average of its recent magnitude" 機械学習コースの講義スライドと動画
Adam
時々聞く冗談で、アダムは人名?ではありません😆「Adaptive Moment」からの組み合わせです。2014年にversion 1として発表されているようです。2017年でversion 9となっていました。
論文の参考文献だと、RMSPropは Tieleman と Hinton の2名によるLecture 6.5となっているんですよ。記法も教科書・参考書的表記なので安心して読めます。なんとなく嬉しい。
- Kingma and Ba (2014) "Adam: A Method for Stochastic Optimization", arXiv:1412.6980
AdamW
"L2 regularization and weight decay are not identical."から5つ主張が並んでいるのが印象的な論文でした。2017年にversion 1となりますが、論文タイトルが "Fixing Weight Decay Regularization in Adam" となっています。
- Loshchilov and Hutter (2019) "Decoupled Weight Decay Regularization", arXiv:1711.05101
Muon
Muonは、Keller Jordan (2024) の研究ブログによる発表です。Why is it good to orthogonalize the update?の見出し部分に手書き?で文字列を削除したような画像が😆
参考サイト
書籍やネット記事も大変参考になりました。今回の内容は数学よりの深層学習の教科書だとほぼ記載されている内容となります![]()
-
- 数式やグラフでの説明があり参考になりました。
-
【決定版】スーパーわかりやすい最適化アルゴリズム -損失関数からAdamとニュートン法-
- QiitaのAI関連で知らない人はいない?omiita氏の解説記事。グラフでの動きがとても参考になります。もう更新が無いのかな少し残念な気もします。
-
- 参考にしているサイトのひとつ。L1/L2正則化について詳しく書かれています。
-
- 用語が網羅的に掲載されています。直感的な理解に役立つと思います。
注
-
ミニバッチ化されている場合は、ミニバッチを考えた損失関数$L_{B_t}(\theta_{t-1})$を作り、損失関数$L_{B_t}$の勾配ベクトルとして、記号$g_t = \nabla L_{B_t}(\theta_t)$を使います。$E[g_t|\theta_{t-1}]=\nabla L(\theta_{t-1})$という全データの勾配の不偏推定量となります。まあ、深く考えず$g_t = \nabla L_{t}(\theta_{t-1})$でいいかと思います。 ↩
-
μ=βで指数移動平均の形になります。私は今までこのような機能があることを知りませんでした
オプティマイザーの世界は深いようです。 ↩ -
PyTorchでのNesterovの実装方法は数式そのものではないようです。後でじっくり確認してみたい。 ↩
-
分母の 極小の $\varepsilon >0$ によって分母が0になることを防いでいます。 ↩
-
AdamにL2正則化をそのまま加えると、Adamに渡される勾配そのものが
$$
g_t^{reg}=g_t+\lambda\theta_{t-1}
$$
となります。1次・2次の$g_t$が$g_t^{reg}$になるので、代入された値は
$$
m_t = \beta_1m_{t-1} + (1-\beta_1) (g_t+\lambda\theta_{t-1}) \
v_t = \beta_2v_{t-1} + (1-\beta_2) (g_t+\lambda\theta_{t-1})^2
$$
のようになります。L2正則化の$\lambda\theta_{t-1}$がAdamの1次・2次モーメントの計算に影響を与えることになります。上手く表現できなかった
L2正則化とAdamの適応的な勾配調整が混ざってしまうということです。 ↩ -
表記を簡略にするために$G_t$としていますが、ネットワーク層毎に考えます。$k$層目のパラメータだと$G_t^k$みたいなイメージです。 ↩
-
実装ではいつものように $||B_t||_F = 0$ のときのゼロ除算を避けるため、分母に極小さな定数 $\varepsilon$が足し算されます。 ↩
-
デフォルト値は $(a, b, c) = (3.4445, -4.775, 2.0315)$とされています。自分は詳しくないのでこの数値を操作することはなさそう。 ↩