天天看點

深度學習常見優化算法,圖解AdaGrad、RMSProp,Adam

1. AdaGrad

AdaGrad算法是梯度下降法的改進算法,其優點是可以自适應學習率。該優化算法在較為平緩處學習速率大,有比較高的學習效率,在陡峭處學習率小,在一定程度上可以避免越過極小值點。在SDG優化算法中不能自适應學習率,如圖1所示,在函數的初始位置比較平緩,利用AdaGrad優化算法可以很快的到達較優點,而SGD幾乎沒有移動。如圖2所示,初始位置比較陡峭,AdaGrad優化算法會自動調整學習率,然後順利的到達最優點,而SGD在學習率比較大的情況下會在斜坡兩邊來回擺動。AdaGrad的公式如下:

σ t = 1 t + 1 ∑ i = 0 t ( g i ) 2 \sigma^t=\sqrt{\frac{1}{t+1}\sum^{t}_{i = 0}{(g_i)^2}} σt=t+11​i=0∑t​(gi​)2

θ t + 1 = θ t − η σ t + ψ g t \theta^{t+1}=\theta^t-\frac{\eta}{\sigma^t+\psi}g^t θt+1=θt−σt+ψη​gt 其中 g i g_i gi​代表函數第 i i i次疊代的梯度, σ t \sigma^t σt就是前面所有梯度的均值平方根。 η \eta η是常數,一般取 1 0 − 7 10^{-7} 10−7,這是為了避免公式中分母為存在等于0的情況。 η \eta η為常數,表示學習率。

示範代碼見文章末尾附錄部分
深度學習常見優化算法,圖解AdaGrad、RMSProp,Adam
深度學習常見優化算法,圖解AdaGrad、RMSProp,Adam

2. RMSProp

AdaGrad算法雖然解決了學習率無法根據目前梯度自動調整的問題,但是過于依賴之前的梯度,在梯度突然變化無法快速響應。RMSProp算法為了解決這一問題,在AdaGrad的基礎上添加了衰減速率參數。也就是說在目前梯度與之前梯度之間添加了權重,如果目前梯度的權重較大,那麼響應速度也就更快。RMSProp公式如下:

σ t = α ( 1 t ∑ i = 0 t − 1 ( g i ) 2 ) + ( 1 − α ) ( g t ) 2 \sigma_t=\sqrt{\alpha(\frac{1}{t}\sum^{t-1}_{i = 0}{(g_i)^2})+(1-\alpha)(g^t)^2} σt​=α(t1​i=0∑t−1​(gi​)2)+(1−α)(gt)2

θ t + 1 = θ t − η σ t + ψ g t \theta_{t+1}=\theta_t-\frac{\eta}{\sigma_t+\psi}g^t θt+1​=θt​−σt​+ψη​gt 公式中 α \alpha α越大,那麼受到之前梯度的影響就越大,AdaGrad算法和RMSProp算法比較如圖3所示:

深度學習常見優化算法,圖解AdaGrad、RMSProp,Adam

3. Adam

Adam優化算法是在RMSProp的基礎上增加了動量。有時候通過RMSProp優化算法得到的值不是最優解,有可能是局部最優解,引入動量的概念時,求最小值就像一個球從高處落下,落到局部最低點時會繼續向前探索,有可能得到更小的值,如下圖4所示,Adam的公式如下:

m t = β ⋅ m t − 1 + ( 1 − β ) g t − 1 m_t=\beta·m_{t-1}+(1-\beta)g^{t-1} mt​=β⋅mt−1​+(1−β)gt−1

σ t = α ( 1 t ∑ i = 0 t − 1 ( g i ) 2 ) + ( 1 − α ) ( g t ) 2 \sigma_t=\sqrt{\alpha(\frac{1}{t}\sum^{t-1}_{i = 0}{(g_i)^2})+(1-\alpha)(g^t)^2} σt​=α(t1​i=0∑t−1​(gi​)2)+(1−α)(gt)2

θ t = θ t − 1 + η σ t + ψ m t \theta_t=\theta_{t-1}+\frac{\eta}{\sigma_t+\psi}m_t θt​=θt−1​+σt​+ψη​mt​ 其中 m t m_t mt​表示第t次疊代時的動量,同時在上一次動量和本次梯度之間加了一個權重系數 β \beta β,當 β \beta β越大,受到上一次動量的影響就越大。

torch.optim.Adam

Adam函數的常用參數如下:

  • params (iterable) – 需要優化的參數,參數類型為疊代器或字典。
  • lr (float, optional) – 學習率 (預設值: 1e-3)
  • betas (Tuple[float, float], optional) – 權重值,分别代表上面公式中的 α \alpha α和 β \beta β (預設值: (0.9, 0.999))
深度學習常見優化算法,圖解AdaGrad、RMSProp,Adam

參考文獻

[1] 深度學習常見的優化算法

[2] Adam 算法

[3] torch 官方文檔

附錄

圖1代碼

import torch
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 初始化變量
adaGrad_x = torch.tensor(-10., requires_grad=True)
sgd_x = torch.tensor(-10., requires_grad=True)
adaGrad_optimizer = torch.optim.Adagrad([adaGrad_x], lr=1)
sgd_optimizer = torch.optim.SGD([sgd_x], lr=1)

# 200次疊代優化
adaGrad_x_record, adaGrad_y_record = [], []
sgd_x_record, sgd_y_record = [], []
for i in range(200):
    # AdaGrad
    adaGrad_y = 1/(1 + torch.exp(adaGrad_x))
    adaGrad_x_record.append(adaGrad_x.detach().item())
    adaGrad_y_record.append(adaGrad_y.detach().item())
    adaGrad_optimizer.zero_grad()
    adaGrad_y.backward()
    adaGrad_optimizer.step()

    # SGD
    sgd_y = 1/(1 + torch.exp(sgd_x))
    sgd_x_record.append(sgd_x.detach().item())
    sgd_y_record.append(sgd_y.detach().item())
    sgd_optimizer.zero_grad()
    sgd_y.backward()
    sgd_optimizer.step()

# y = 1/(1+e^x)
a = torch.linspace(-10, 10, 1000)
b = 1/(1 + torch.exp(a))

# 建立畫布
plt.figure(figsize=(12, 4))

# AdaGrad
plt.subplot(1, 2, 1)
plt.plot(a, b)
plt.scatter(adaGrad_x_record, adaGrad_y_record, c='r', alpha=0.5)
plt.title('AdaGrad')
plt.grid()
# SGD
plt.subplot(1, 2, 2)
plt.plot(a, b)
plt.scatter(sgd_x_record, sgd_y_record , c='r', alpha=0.5)
plt.title('SGD')
plt.grid()
# 顯示圖檔
plt.suptitle('圖1', y=0)
plt.show()
           

圖2代碼

import torch
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

adaGrad_x = torch.tensor(-10., requires_grad=True)
sgd_x = torch.tensor(-10., requires_grad=True)
adaGrad_optimizer = torch.optim.Adagrad([adaGrad_x], lr=1)
sgd_optimizer = torch.optim.SGD([sgd_x], lr=1)

# 100次疊代優化
adaGrad_x_record, adaGrad_y_record = [], []
sgd_x_record, sgd_y_record = [], []
for i in range(100):
    # AdaGrad
    adaGrad_y = adaGrad_x ** 2
    adaGrad_x_record.append(adaGrad_x.detach().item())
    adaGrad_y_record.append(adaGrad_y.detach().item())
    adaGrad_optimizer.zero_grad()
    adaGrad_y.backward()
    adaGrad_optimizer.step()

    # SGD
    sgd_y = sgd_x ** 2
    sgd_x_record.append(sgd_x.detach().item())
    sgd_y_record.append(sgd_y.detach().item())
    sgd_optimizer.zero_grad()
    sgd_y.backward()
    sgd_optimizer.step()

# y = x^2
a = torch.linspace(-10, 10, 1000)
b = a ** 2

# 建立畫布
plt.figure(figsize=(12, 4))

# AdaGrad
plt.subplot(1, 2, 1)
plt.plot(a, b)
plt.scatter(adaGrad_x_record, adaGrad_y_record, c='r', alpha=0.5)
plt.title('AdaGrad')
plt.grid()
# SGD
plt.subplot(1, 2, 2)
plt.plot(a, b)
plt.scatter(sgd_x_record, sgd_y_record , c='r', alpha=0.5)
plt.title('SGD')
plt.grid()
# 顯示圖檔
plt.suptitle('圖2', y=0)
plt.show()
           

圖3代碼

import torch
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 初始化變量
adaGrad_x = torch.tensor(-20., requires_grad=True)
rmsProp_x = torch.tensor(-20., requires_grad=True)
adaGrad_optimizer = torch.optim.Adagrad([adaGrad_x], lr=1)
rmsProp_optimizer = torch.optim.RMSprop([rmsProp_x], lr=1)

# 200次疊代優化
adaGrad_x_record, adaGrad_y_record = [], []
rmsProp_x_record, rmsProp_y_record = [], []
for i in range(200):
    # AdaGrad
    adaGrad_y = 1/(1 + torch.exp(adaGrad_x))
    adaGrad_x_record.append(adaGrad_x.detach().item())
    adaGrad_y_record.append(adaGrad_y.detach().item())
    adaGrad_optimizer.zero_grad()
    adaGrad_y.backward()
    adaGrad_optimizer.step()

    # RMSProp
    rmsProp_y = 1/(1 + torch.exp(rmsProp_x))
    rmsProp_x_record.append(rmsProp_x.detach().item())
    rmsProp_y_record.append(rmsProp_y.detach().item())
    rmsProp_optimizer.zero_grad()
    rmsProp_y.backward()
    rmsProp_optimizer.step()

# y = 1/(1+e^x)
a = torch.linspace(-20, 20, 1000)
b = 1/(1 + torch.exp(a))

# 建立畫布
plt.figure(figsize=(12, 4))

# AdaGrad
plt.subplot(1, 2, 1)
plt.plot(a, b)
plt.scatter(adaGrad_x_record, adaGrad_y_record, c='r', alpha=0.5)
plt.title('AdaGrad')
plt.grid()
# RMSProp
plt.subplot(1, 2, 2)
plt.plot(a, b)
plt.scatter(rmsProp_x_record, rmsProp_y_record , c='r', alpha=0.5)
plt.title('RMSProp')
plt.grid()
# 顯示圖檔
plt.suptitle('圖3', y=0)
plt.show()
           

圖4代碼

import torch
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 初始化變量
rmsProp_x = torch.tensor(-10., requires_grad=True)
adam_x = torch.tensor(-10., requires_grad=True)
rmsProp_optimizer = torch.optim.RMSprop([rmsProp_x], lr=1)
adam_optimizer = torch.optim.Adam([adam_x], lr=1, betas=(0.9, 0.61))

# 40次疊代優化
rmsProp_x_record, rmsProp_y_record = [], []
adam_x_record, adam_y_record = [], []
for i in range(40):
    # RMSProp
    rmsProp_y =  16 * rmsProp_x ** 2 - rmsProp_x ** 3
    rmsProp_x_record.append(rmsProp_x.detach().item())
    rmsProp_y_record.append(rmsProp_y.detach().item())
    rmsProp_optimizer.zero_grad()
    rmsProp_y.backward()
    rmsProp_optimizer.step()

    # Adam
    adam_y =  16 * adam_x ** 2 - adam_x ** 3
    adam_x_record.append(adam_x.detach().item())
    adam_y_record.append(adam_y.detach().item())
    adam_optimizer.zero_grad()
    adam_y.backward()
    adam_optimizer.step()

# y = 16*x^2-x^3
a = torch.linspace(-10., 20., 1000)
b = 16 * a ** 2 - a ** 3

# 建立畫布
plt.figure(figsize=(12, 4))

# RMSProp
plt.subplot(1, 2, 1)
plt.plot(a, b)
plt.scatter(rmsProp_x_record, rmsProp_y_record, c='r', alpha=0.5)
plt.title('RMSProp')
plt.grid()
# Adam
plt.subplot(1, 2, 2)
plt.plot(a, b)
plt.scatter(adam_x_record, adam_y_record , c='r', alpha=0.5)
plt.title('Adam')
plt.grid()
# 顯示圖檔
plt.suptitle('圖4', y=0)
plt.show()
           

繼續閱讀