使用Numpy進行深度學習的5大優化算法的性能比較

在本文中,我們將通過計算二次凸函數的最優點來數值比較主要的深度學習優化算法的性能。

簡介

深度學習被稱爲人工智能的未來。現在,神經網絡被稱爲通用函數逼近器,也就是說,它們有能力表示這個宇宙中任何複雜的函數。計算這個具有數百萬個參數的通用函數的想法來自優化的基本數學。優化可以通過多種方式完成,但在本文中,我們將重點討論基於梯度下降的優化技術。

非凸函數的優化是研究的主要領域。多年來,不同的科學家提出了不同的優化算法來優化神經網絡的成本函數。這些算法大部分都是基於梯度的方法,稍作修改。在這篇文章中,我們將討論5個專業的下降基於算法-梯度下降,動量,Adagrad, RMSprop, Adam。

方法

爲了瞭解每個算法在實際中是如何工作的,我們將使用一個凸二次函數。我們將對每個算法進行固定次數的迭代(20次),以比較它們在達到最優點時的收斂速度和軌跡。下面給出了爲此任務選擇的函數的方程,以及使用Matplotlib繪製的函數的三維圖和級別集。


import matplotlib.pyplot as plt
fig = plt.figure(figsize=(13,6))
ax = plt.axes(projection="3d") 
start, stop, n_values = -8, 8, 800
x_vals = np.linspace(start, stop, n_values)
y_vals = np.linspace(start, stop, n_values)
X, Y = np.meshgrid(x_vals, y_vals)
Z = np.sqrt(0.1*X**2 + 2*Y**2)
plt.contourf(X,Y,Z,)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='winter', edgecolor='none')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

首先,我們將從最基本的梯度下降算法開始,然後我們將跟隨它們發展的趨勢來支持每個算法發展背後的想法。所以趨勢是這樣的

1-Gradient Descent

2-Momentum

3-Adagrad

4-RMSprop

5-Adam

因爲所有這些算法在更新規則的每次迭代時都需要梯度。因此,下面給出了函數的梯度,用於在每次迭代時更新兩個變量。我們將對所有算法使用固定的學習率值=0.4。

1、Gradient Descent

梯度下降法是求解最優解的最傳統的方法。在這個算法中,使用當前梯度(gt)乘以一些稱爲學習率的因子來更新當前權值。更新規則的公式如下所示。

lr=0.4
x1=-4
x2=-6
l1_gd=[]
l2_gd=[]
for i in range(20):
  l1_gd.append(x1)
  l2_gd.append(x2)
  x1=x1-lr*0.2*x1
  x2=x2-lr*4*x2

使用梯度下降的軌跡

fig = plt.figure(figsize=(13,6))
left, bottom, width, height = 100, 0.1, 0.8, 0.8

ax = fig.add_axes([left, bottom, width, height]) 

start, stop, n_values = -8, 8, 100

x_vals = np.linspace(start, stop, n_values)
y_vals = np.linspace(start, stop, n_values)
X, Y = np.meshgrid(x_vals, y_vals)


Z = np.sqrt(0.1*X**2 + 2*Y**2)

plt.contourf(X,Y,Z,)

plt.plot(l1_gd[:15],l2_gd[:15],color="red",marker="*",markeredgecolor="black",linewidth=3,label="Gradient Descent")

plt.figure(figsize=(15,10))
plt.figure(figsize=(15,10))
ax.set_title('Level Sets of the Function',size=20)
ax.set_xlabel('x (cm)')
ax.set_ylabel('y (cm)')
ax.legend()


plt.show()

正如我們在上面的圖中看到的,梯度下降經歷了很多振盪,收斂速度非常慢。所以在後面的部分,我們將學習梯度下降的改進,它將幫助我們實現穩定和更快的收斂。

2、Momentum

動量梯度下降是一種常用的優化器,它消除了標準梯度下降引起的振盪,加速了收斂最優點。當它在水平方向上加速時,它在垂直方向上減速。在這種傑出行爲的幫助下,它使我們在學習率的方向上邁出了一大步。此外,動量比標準梯度下降要穩定得多。

下面給出的方程式解釋了更新規則-

v1,v2=0,0
gamma,lr=0.5,0.4
x1,x2=-4,-6
l1_gd_m,l2_gd_m=[],[]
for i in range(20):
  l1_gd_m.append(x1)
  l2_gd_m.append(x2)
  v1=gamma*v1+(0.2*x1)
  v2=gamma*v2+(4*x2)
  x1=x1-lr*v1
  x2=x2-lr*v2

Gradient Descent vs Momentum

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(13,6))
left, bottom, width, height = 100, 0.1, 0.8, 0.8

ax = fig.add_axes([left, bottom, width, height]) 

start, stop, n_values = -8, 8, 100

x_vals = np.linspace(start, stop, n_values)
y_vals = np.linspace(start, stop, n_values)
X, Y = np.meshgrid(x_vals, y_vals)


Z = np.sqrt(0.1*X**2 + 2*Y**2)

plt.contourf(X,Y,Z,)

plt.plot(l1_gd[:15],l2_gd[:15],color="red",marker="*",markeredgecolor="black",linewidth=3,label="Gradient Descent")
plt.plot(l1_gd_m[:15],l2_gd_m[:15],color="yellow",marker="*",markeredgecolor="orange",linewidth=3,label="Gradient Descent (Momentum =0.5)")

plt.figure(figsize=(15,10))
plt.figure(figsize=(15,10))
ax.set_title('Level Sets of the Function',size=20)
ax.set_xlabel('x (cm)')
ax.set_ylabel('y (cm)')
ax.legend()


plt.show()

3、Adagrad

自適應梯度下降算法(adaptive gradient descent)是一種學者梯度下降算法。其主要區別在於Adagrad根據網絡中參數的重要性對每個權值利用不同的學習速率。換句話說,用較高的學習率訓練不必要的參數,用較小的學習率訓練重要參數,使其更穩定地收斂。在不允許失真的情況下,實現了算法的加速。更新公式類似於動量,這裏每一步的動量是用之前的動量和梯度的平方來計算的。下面的公式顯示了Adagrad中的更新規則。


Gt是一個對角矩陣組成的平方和過去的漸變和ϵ平滑項。此外,表示矩陣-向量積運算。

v1,v2=0,0
gamma,lr=0.9,0.4
x1,x2=-4,-6
l1_adagrad,l2_adagrad=[],[]
for i in range(20):
  l1_adagrad.append(x1)
  l2_adagrad.append(x2)
  v1=v1+(0.2*x1)**2
  v2=v2+(4*x2)**2
  x1=x1-(lr/math.sqrt(v1+c))*0.2*x1
  x2=x2-(lr/math.sqrt(v2+c))*4*x2

Momentum vs Adagrad

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(13,6))
left, bottom, width, height = 100, 0.1, 0.8, 0.8

ax = fig.add_axes([left, bottom, width, height]) 

start, stop, n_values = -8, 8, 100

x_vals = np.linspace(start, stop, n_values)
y_vals = np.linspace(start, stop, n_values)
X, Y = np.meshgrid(x_vals, y_vals)


Z = np.sqrt(0.1*X**2 + 2*Y**2)

plt.contourf(X,Y,Z,)

plt.plot(l1_gd[:15],l2_gd[:15],color="red",marker="*",markeredgecolor="black",linewidth=3,label="Gradient Descent")
plt.plot(l1_gd_m[:15],l2_gd_m[:15],color="yellow",marker="*",markeredgecolor="orange",linewidth=3,label="Gradient Descent (Momentum =0.5)")
plt.plot(l1_adagrad[:15],l2_adagrad[:15],color="blue",marker="*",markeredgecolor="black",linewidth=3,label="Adagrad")
plt.figure(figsize=(15,10))
plt.figure(figsize=(15,10))
ax.set_title('Level Sets of the Function',size=20)
ax.set_xlabel('x (cm)')
ax.set_ylabel('y (cm)')
ax.legend()


plt.show()

從上圖中可以看出,Adagrad雖然運動平穩無振盪,但收斂能力不足。爲了解決這個問題,Geoffrey Hinton引入了一個更有效的優化器RMSprop。

4、RMSprop

Rmsprop是由著名計算機科學家Geoffrey Hinton (Hinton et al., 2012)提出的另一種高效優化算法。該算法的工作原理與Adagrad相似,只是稍加修改。不像AdaGrad那樣取梯度平方的累積和,我們取這些梯度的指數移動平均值。使用指數平均的原因是爲了給最近更新的梯度權重大於最近更新的梯度。下面的方程式顯示了Rmsprop的更新規則。

v1,v2=0,0
gamma,lr=0.9,0.4
x1,x2=-4,-6
l1,l2=[],[]
for i in range(20):
  l1.append(x1)
  l2.append(x2)
  v1=gamma*v1+(1-gamma)*(0.2*x1)**2
  v2=gamma*v2+(1-gamma)*(4*x2)**2
  x1=x1-(lr/math.sqrt(v1+c))*0.2*x1
  x2=x2-(lr/math.sqrt(v2+c))*4*x2

Momentum vs Adagrad vs RMSprop

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(13,6))
left, bottom, width, height = 100, 0.1, 0.8, 0.8

ax = fig.add_axes([left, bottom, width, height]) 

start, stop, n_values = -8, 8, 100

x_vals = np.linspace(start, stop, n_values)
y_vals = np.linspace(start, stop, n_values)
X, Y = np.meshgrid(x_vals, y_vals)


Z = np.sqrt(0.1*X**2 + 2*Y**2)

plt.contourf(X,Y,Z,)

plt.plot(l1_gd[:15],l2_gd[:15],color="red",marker="*",markeredgecolor="black",linewidth=3,label="Gradient Descent")
plt.plot(l1_gd_m[:15],l2_gd_m[:15],color="yellow",marker="*",markeredgecolor="orange",linewidth=3,label="Gradient Descent (Momentum =0.5)")
plt.plot(l1_adagrad[:15],l2_adagrad[:15],color="blue",marker="*",markeredgecolor="black",linewidth=3,label="Adagrad")
plt.plot(l1[:15],l2[:15],color="g",marker="*",markeredgecolor="b",linewidth=3,label="RMSprop Algorithm")
plt.figure(figsize=(15,10))
plt.figure(figsize=(15,10))
ax.set_title('Level Sets of the Function',size=20)
ax.set_xlabel('x (cm)')
ax.set_ylabel('y (cm)')
ax.legend()


plt.show()

顯而易見,當收斂到最優點時,梯度下降算法在垂直方向上產生巨大的振盪,RMSprop限制了垂直運動,加速了水平方向。此外,雖然動量減小了振盪,RMSprop提供了更可靠和更快的收斂。

5、Adam

自適應矩估計是另一種計算每個參數的自適應學習率的優化器。與其他優化器相比,它更加健壯和可靠,因爲它基本上結合了動量和RMSprop(即。移動類似梯度的動量的平均值,並使用梯度的平方來調整學習速率,如RMSprop)。更精確地說,Adam算法執行如下-

v1,v2,s1,s2=0,0,0,0
gamma,beta,lr=0.9,0.999,0.4
x1,x2=-6,-6
l1_adam,l2_adam=[],[]
for i in range(20):
  l1_adam.append(x1)
  l2_adam.append(x2)
  v1=gamma*v1+(1-gamma)*(0.2*x1)
  v2=gamma*v2+(1-gamma)*(4*x2)
  s1=beta*s1+(1-beta)*(0.2*x1)**2
  s2=beta*s2+(1-beta)*(4*x2)**2
  m_hat_v1= v1 / (1 - np.power(gamma, i+1))
  m_hat_v2 = v2 / (1 - np.power(gamma, i+1))
  s_hat_s1= s1 / (1 - np.power(beta, i+1))
  s_hat_s2 = s2 / (1 - np.power(beta, i+1))
  x1=x1-(lr)*(m_hat_v1/math.sqrt((s_hat_s1)+c))
  x2=x2-(lr)*(m_hat_v2/math.sqrt((s_hat_s2)+c))
  print(x1,x2)
  if abs(x1)<=0.1 and abs(x2)<0.1:
    break

在收斂期間的軌跡彙總

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(13,6))
left, bottom, width, height = 100, 0.1, 0.8, 0.8

ax = fig.add_axes([left, bottom, width, height]) 

start, stop, n_values = -8, 8, 100

x_vals = np.linspace(start, stop, n_values)
y_vals = np.linspace(start, stop, n_values)
X, Y = np.meshgrid(x_vals, y_vals)


Z = np.sqrt(0.1*X**2 + 2*Y**2)

plt.contourf(X,Y,Z,)

plt.plot(l1_gd[:15],l2_gd[:15],color="red",marker="*",markeredgecolor="black",linewidth=3,label="Gradient Descent")
plt.plot(l1_gd_m[:15],l2_gd_m[:15],color="yellow",marker="*",markeredgecolor="orange",linewidth=3,label="Gradient Descent (Momentum =0.5)")
plt.plot(l1_adagrad[:15],l2_adagrad[:15],color="blue",marker="*",markeredgecolor="black",linewidth=3,label="Adagrad")
plt.plot(l1[:15],l2[:15],color="g",marker="*",markeredgecolor="b",linewidth=3,label="RMSprop Algorithm")
plt.plot(l1_adam[:20],l2_adam[:20],color="Brown",marker="*",markeredgecolor="pink",linewidth=3,label="Adam")
plt.figure(figsize=(15,10))
plt.figure(figsize=(15,10))
ax.set_title('Level Sets of the Function',size=20)
ax.set_xlabel('x (cm)')
ax.set_ylabel('y (cm)')
ax.legend()


plt.show()

正如在最後的圖中所看到的,Adam優化器在直線路徑上導致最快的收斂。在Adam的例子中,它通過累積之前梯度的總和來減弱振盪,並且由於梯度的平方項,它遵循一條直線,類似於RMSprop。這導致了一個明顯的結論,即Adam是Momentum和RMSprop的結合版本。從上圖中我們可以很容易地看出爲什麼Adam是deep learning中最流行的優化器。即使從離最優值(-6,-6)很遠的地方開始,Adam也能以最小的迭代收斂得最快。

作者:Saket Thavanani

本文代碼地址:https://github.com/Saket-Uoft/Deep-Learning-Optimizers

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章