Optimizer 3


Prologue


勾配降下発展の方向は大きく2つある.1つ目は物理の法則に従う方法です.第2の方法は,学習回数の増加に伴い,一定の割合で学習率を減少させ,グローバル最小値を超えないようにすることである.今回知っておきたいのは、2つの方法を組み合わせて使用するアルゴリズムです.
import numpy as np
import matplotlib.pyplot as plt

def f(x, y):
    return 0.4*x**2*y**2 + 0.3*x**2*y + 0.3*x**2 + 0.3*y**2 - 0.25*x*y**2 + 0.31*x*y - 0.2*x + 2.1*y

def df(x, y):
    dx = 0.8*x*y**2 + 0.6*y + 0.6*x - 0.5*y + 0.31*y - 0.2
    dy = 0.8*x**2*y + 0.6*x**2 + 0.6*y - 0.5*x*y + 0.31*x + 2.1
    return dx, dy

x = np.arange(-1, 2, 0.01)
y = np.arange(-2, 1, 0.01)
X, Y = np.meshgrid(x, f(x, y))
Z = np.sqrt(X**2 + Y**2)
plt.contour(X, Y, Z, 25, colors = ['gray'])
plt.plot(x, f(x, y))

私たちはヘメルコンボル地形です.2 D二次関数にz軸を追加し、等高線のように高さが等しい支点間を立体化します.最小の円は最小値を持つため、オプティマイザは円を低くすることができます.

Adam


MomentumとRMSPropを統合するアルゴリズム.両方のアルゴリズムが良ければ、統合したほうがいいのではないでしょうか.中には作っているIntutionが入っています混ざっているせいか複雑ですがどこに置いても良いのでよく使います.
mn=β1mn−1+(1−β1)∇f(θn), m1=0m_n =\beta_1 m_{n-1}+(1-\beta_1)\nabla f(\theta_n),\m_1 =0mn​=β1​mn−1​+(1−β1​)∇f(θn​), m1​=0
vn=β2vn−1+(1−β2)∇f(θn)⊙∇f(θn), v1=0v_n=\beta_2 v_{n-1}+(1-\beta_2)\nabla f(\theta_n)\odot\nabla f(\theta_n),\v_1 = 0vn​=β2​vn−1​+(1−β2​)∇f(θn​)⊙∇f(θn​), v1​=0
このときβ1\beta_1β第1課β2\beta_2β2の初期値はそれぞれ0.99と0.999であった.α\alphaα10,310^{−3}10σ3と命名した.このように、m 1 m 1 m 1 m 1およびv 1 v 1 v 1は0であるため、第1ステップの結リンゴ値は0になる傾向があるため、vnv nvnおよびhnh nhnを以下のように修正する.
m^n=mn1−β1n+1v^n=vn1−β2n+1\hat{m}_n=\cfrac{m_n}{1-\beta_1^{n+1}}\quad\quad\quad\hat{v}_n=\cfrac{v_n}{1-\beta_2^{n+1}}m^n​=1−β1n+1​mn​​v^n​=1−β2n+1​vn​​
したがって,点の移動は従来のアルゴリズムよりも複雑である.
θn+1=θn−α1mn^⊙v^\theta_{n+1}=\theta_{n}-\alpha\cfrac{1}{\sqrt{\hat{m_n}}}\odot\hat{v}θn+1​=θn​−αmn​^​​1​⊙v^
少し考えてみると、勉強が進むにつれて、m^hat{m}m^とv^hat{v}v^がmmmとnnnに近づき、結局SGDに似ている.
def adam(x, y, cache: dict, beta1 = 0.9, beta2 = 0.999, lr= 5e-2):
    t = 0
    dx, dy = df(x, y)
    if len(cache['m']['x']) == 0 and len(cache['v']['y']) == 0:
        mx = (1 - beta1) * dx
        my = (1 - beta1) * dy
        vx = (1 - beta2) * np.square(dx)
        vy = (1 - beta2) * np.square(dy)
    else:
        mx = beta1 * cache['m']['x'][-1] + (1 - beta1) * dx
        my = beta1 * cache['m']['y'][-1] + (1 - beta1) * dy
        vx = beta2 * cache['v']['x'][-1] + (1 - beta2) * np.square(dx)
        vy = beta2 * cache['v']['y'][-1] + (1 - beta2) * np.square(dy)
    t += 1
    cache['m']['x'].append(mx)
    cache['m']['y'].append(my)
    cache['v']['x'].append(vx)
    cache['v']['y'].append(vy)
    hat_mx = mx / (1 - beta1**t)
    hat_my = my / (1 - beta1**t)  
    hat_vx = vx / (1 - beta2**t)
    hat_vy = vy / (1 - beta2**t)
    x = x - lr * hat_mx / (np.sqrt(hat_vx)- 1e-8)
    y = y - lr * hat_my / (np.sqrt(hat_vy)- 1e-8)
    return x, y

cache = {'v':{'x':[], 'y':[]}, 'm':{'x':[], 'y':[]}}
adamX, adamY = [.5], [5.8]
x, y = adam(*adamX, *adamY, cache)
adamX.append(x)
adamY.append(y)
for i in range(92):
    x, y = adam(x, y, cache)
    adamX.append(x)
    adamY.append(y)
    
plt.contour(X, Y, Z, 25, colors= ['gray'])
plt.plot(adamX, adamY)
plt.title('Adam')
plt.xlabel('lr=5e-2, epochs=92')

2つの特性が混在しているためか,この課題ではSGDよりも基本設定が収束しにくく,アルゴリズムはより高い学習率を要求しているようである.

Epilogue


  • アルゴリズムに大きな影響を及ぼしたのは学習率と時代である.
  • できるだけアダムとRMSPropを試してみましょう.
  • これまで,2次元極小値探索の課題においても,各アルゴリズムの個性がうかがえる.MNISTでもFCLで解決しようとする問題は784次元ですが、私たちが通常処理しなければならない課題は数千万、数億次元のモデルなので、minimaを探す任務はそんなに簡単ではありません.