代碼詳解:運用Numpy實現梯度降低優化算法的不一樣變體

全文共14118字,預計學習時長30分鐘或更長html

想了解如何使用numpy在tensorflow或pytorch中實現優化算法,以及如何使用matplotlib建立精美的動畫?git

本文將討論如何實現梯度降低優化技術的不一樣變體,以及如何使用matplotlib將用於這些變體更新規則的運做可視化出來。github

本文的內容和結構基於 One-Fourth Labs。算法

梯度降低是優化神經網絡最經常使用的技術之一。梯度降低算法是經過向相對於網絡參數的目標函數梯度的相反方向移動來更新參數。數組

運用Numpy在Python中實現微信

照片來源:Unsplash,克里斯托弗·高爾網絡

編碼部分將討論如下主題。app

• Sigmoid神經元類ide

• 整體設置——何爲數據、模型、任務函數

• 繪圖功能——3D和輪廓圖

• 個體算法及其執行方式

在開始實現梯度降低以前,首先須要輸入所需的庫。從mpl_toolkits.mplot3d輸入的Axes3D提供了一些基本的3D繪圖(散點、曲面、直線、網格)工具。它並不是最快或功能最完整的3D庫,而是Matplotlib附帶的。還從 Matplotlib輸入colors和colormap(cm)。咱們想要製做動畫圖來演示每種優化算法的工做原理,因此咱們輸入animation和rc來讓圖表看起來美觀。爲了顯示HTML,在Jupyter Notebook中成線性排列。最後爲了計算目的來輸入numpy,這項計算任務很繁重。

from mpl_toolkits.mplot3d import Axes3D

import matplotlib.pyplot as plt

from matplotlib import cm

import matplotlib.colors

from matplotlib import animation, rc

from IPython.display import HTML

import numpy as np

實施Sigmoid神經元

爲了實現梯度降低優化技術,以sigmoid神經元(邏輯函數)爲例,看看梯度降低的不一樣變體是如何學習參數「 w」和「 b」的。

Sigmoid神經元複查

Sigmoid神經元相似於感知機神經元(perceptron neuron),由於對於每一個輸入xi,其都有與輸入相關的權重wi。權重代表了輸入在決策過程當中的重要性。來自sigmoid的輸出不一樣於感知機模型,其輸出不是0或1,而是一個介於0到1之間的實數值,能夠解釋爲機率。最經常使用的sigmoid 函數是邏輯函數,它具備「 S」形曲線的特徵。

Sigmoid神經元標註(邏輯函數)

學習算法

學習算法的目標是肯定參數(w和b)的最佳可能值,以使模型的總體損失(平方偏差損失)儘量最小化。

對w和b進行隨機初始化。而後,對數據中的全部觀測值進行迭代。使用sigmoid函數找到每一個觀測值相應的預測結果,並計算均方偏差損失。基於損失值,將更新權重,以使在新參數下模型的總體損失將小於模型的當前損失。

Sigmoid神經元類

在開始分析梯度降低算法的不一樣變體以前,將在名爲SN的類中構建模型。

class SN:

#constructor

def __init__(self, w_init, b_init, algo):

self.w = w_init

self.b = b_init

self.w_h = []

self.b_h = []

self.e_h = []

self.algo = algo

#logistic function

def sigmoid(self, x, w=None, b=None):

if w is None:

w = self.w

if b is None:

b = self.b

return 1. / (1. + np.exp(-(w*x + b)))

#loss function

def error(self, X, Y, w=None, b=None):

if w is None:

w = self.w

if b is None:

b = self.b

err = 0

for x, y in zip(X, Y):

err += 0.5 * (self.sigmoid(x, w, b) - y) ** 2

return err

def grad_w(self, x, y, w=None, b=None):

if w is None:

w = self.w

if b is None:

b = self.b

y_pred = self.sigmoid(x, w, b)

return (y_pred - y) * y_pred * (1 - y_pred) * x

def grad_b(self, x, y, w=None, b=None):

if w is None:

w = self.w

if b is None:

b = self.b

y_pred = self.sigmoid(x, w, b)

return (y_pred - y) * y_pred * (1 - y_pred)

def fit(self, X, Y,

epochs=100, eta=0.01, gamma=0.9, mini_batch_size=100, eps=1e-8,

beta=0.9, beta1=0.9, beta2=0.9

):

self.w_h = []

self.b_h = []

self.e_h = []

self.X = X

self.Y = Y

if self.algo == 'GD':

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

self.w -= eta * dw / X.shape[0]

self.b -= eta * db / X.shape[0]

self.append_log()

elif self.algo == 'MiniBatch':

for i in range(epochs):

dw, db = 0, 0

points_seen = 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

points_seen += 1

if points_seen % mini_batch_size == 0:

self.w -= eta * dw / mini_batch_size

self.b -= eta * db / mini_batch_size

self.append_log()

dw, db = 0, 0

elif self.algo == 'Momentum':

v_w, v_b = 0, 0

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

v_w = gamma * v_w + eta * dw

v_b = gamma * v_b + eta * db

self.w = self.w - v_w

self.b = self.b - v_b

self.append_log()

elif self.algo == 'NAG':

v_w, v_b = 0, 0

for i in range(epochs):

dw, db = 0, 0

v_w = gamma * v_w

v_b = gamma * v_b

for x, y in zip(X, Y):

dw += self.grad_w(x, y, self.w - v_w, self.b - v_b)

db += self.grad_b(x, y, self.w - v_w, self.b - v_b)

v_w = v_w + eta * dw

v_b = v_b + eta * db

self.w = self.w - v_w

self.b = self.b - v_b

self.append_log()

#logging

def append_log(self):

self.w_h.append(self.w)

self.b_h.append(self.b)

self.e_h.append(self.error(self.X, self.Y))

#constructor

def __init__(self, w_init, b_init, algo):

self.w = w_init

self.b = b_init

self.w_h = []

self.b_h = []

self.e_h = []

self.algo = algo

init__函數(構造函數)有助於將sigmoid神經元的參數初始化爲w權重和b誤差。這個函數有三個參數:

• w_init,b_init,這些取參數「w」和「b」的初始值,而非隨機設置參數,將其設置爲特定值。這樣可以經過可視化不一樣初始點來理解算法的執行方式。有些算法在某些參數下陷入局部最小值。

• algo指出使用何種梯度降低算法的變體來發現最佳參數。

在此函數中,咱們對參數進行初始化,並定義了三種帶有後綴'_h'的新數組變量,表示它們是歷史變量,以跟蹤權重(w_h)、誤差(b_h)和偏差(e_h)的值是如何隨着sigmoid神經元學習參數而變化的。

def sigmoid(self, x, w=None, b=None):

if w is None:

w = self.w

if b is None:

b = self.b

return 1. / (1. + np.exp(-(w*x + b)))

有一個sigmoid函數,它接受輸入x-強制參數,並計算輸入的邏輯函數及參數。該函數還接受其餘兩個可選參數。

• w & b,以「 w」和「 b」用做參數,它有助於根據特定的參數值來計算sigmoid函數的值。若是未傳遞這些參數,它將使用已學的參數值來計算邏輯函數。

def error(self, X, Y, w=None, b=None):

if w is None:

w = self.w

if b is None:

b = self.b

err = 0

for x, y in zip(X, Y):

err += 0.5 * (self.sigmoid(x, w, b) - y) ** 2

return err

下面,有error 函數,輸入X和Y做爲強制參數和可選參數 ,像sigmoid函數同樣。在這個函數中,經過每一個數據點進行迭代,並使用sigmoid函數計算實際特徵值和預測特徵值之間的累積均方偏差。正如在sigmoid函數中看到的,它支持在指定參數值下計算偏差。

def grad_w(self, x, y, w=None, b=None):

.....

def grad_b(self, x, y, w=None, b=None):

.....

接下來,將定義兩個函數grad_w和grad_b。輸入「x」和「y」做爲強制參數,有助於分別計算sigmoid相對於參數「w」和「b」輸入的梯度。還有兩個可選參數,計算指定參數值處的梯度。

def fit(self, X, Y, epochs=100, eta=0.01, gamma=0.9, mini_batch_size=100, eps=1e-8,beta=0.9, beta1=0.9, beta2=0.9):

self.w_h = []

.......

接下來,定義「 fit」法,它接受輸入「 X」,「 Y」和其餘一系列參數。每當將其用於梯度降低算法的特定變體時,都會解釋這些參數。該函數首先初始化歷史記錄變量並設置本地輸入變量以存儲輸入參數數據。

而後,對於該函數支持的每一個算法,有一堆不一樣的「if-else」語句。依據選擇的算法,將在fit法中實現梯度降低。在本文的後半部分,將詳細解釋這些實現。

def append_log(self):

self.w_h.append(self.w)

self.b_h.append(self.b)

self.e_h.append(self.error(self.X, self.Y))

最後,有theappend_log函數,用以存儲各時期各梯度降低的參數值和損失函數值。

繪圖設置

本節將定義一些配置參數,使用簡單的二維toy數據集來模擬梯度降低更新規則。還定義了一些函數,建立三維和二維圖併爲其設置動畫,可視化更新規則的運做。這種設置有助於針對不一樣起點、不一樣超參數設置和不一樣梯度降低變量的繪圖/動畫更新規則運行不一樣的實驗。

#Data

X = np.asarray([3.5, 0.35, 3.2, -2.0, 1.5, -0.5])

Y = np.asarray([0.5, 0.50, 0.5, 0.5, 0.1, 0.3])

#Algo and parameter values

algo = 'GD'

w_init = 2.1

b_init = 4.0

#parameter min and max values- to plot update rule

w_min = -7

w_max = 5

b_min = -7

b_max = 5

#learning algorithum options

epochs = 200

mini_batch_size = 6

gamma = 0.9

eta = 5

#animation number of frames

animation_frames = 20

#plotting options

plot_2d = True

plot_3d = False

首先,採用一個簡單的二維玩具數據集,它包括兩個輸入和兩個輸出。在第5行定義一個字符串變量algo,它接受要執行的算法類型。初始化第6-7行中的參數'w'和'b',以指示算法的開始位置。

從第9-12行開始,設置參數的極限,即signoid神經元在指定範圍內搜索最佳參數的範圍。這些精心挑選的數字,用以說明梯度降低更新規則的運做。接下來將設置超參數的值,將某些變量特定於某些算法。在咱們討論算法實現的時候,我會對此進行討論。最後,從19-22行開始,明確製做動畫或繪製更新規則所需的變量。

sn = SN(w_init, b_init, algo)

sn.fit(X, Y, epochs=epochs, eta=eta, gamma=gamma, mini_batch_size=mini_batch_size)

plt.plot(sn.e_h, 'r')

plt.plot(sn.w_h, 'b')

plt.plot(sn.b_h, 'g')

plt.legend(('error', 'weight', 'bias'))

plt.title("Variation of Parameters and loss function")

plt.xlabel("Epoch")

plt.show()

設置好配置參數後,將SN類進行初始化,而後使用配置參數調用fit法。此外,繪製三個歷史變量,用以將參數和損失函數值在各個時期之間的變化進行可視化。

3D和2D繪圖設置

if plot_3d:

W = np.linspace(w_min, w_max, 256)

b = np.linspace(b_min, b_max, 256)

WW, BB = np.meshgrid(W, b)

Z = sn.error(X, Y, WW, BB)

fig = plt.figure(dpi=100)

ax = fig.gca(projection='3d')

surf = ax.plot_surface(WW, BB, Z, rstride=3, cstride=3, alpha=0.5, cmap=cm.coolwarm, linewidth=0, antialiased=False)

cset = ax.contourf(WW, BB, Z, 25, zdir='z', offset=-1, alpha=0.6, cmap=cm.coolwarm)

ax.set_xlabel('w')

ax.set_xlim(w_min - 1, w_max + 1)

ax.set_ylabel('b')

ax.set_ylim(b_min - 1, b_max + 1)

ax.set_zlabel('error')

ax.set_zlim(-1, np.max(Z))

ax.view_init (elev=25, azim=-75) # azim = -20

ax.dist=12

title = ax.set_title('Epoch 0')

首先爲了建立3D繪圖,要在「 w」和「 b」的最小值和最大值之間建立256個相等間隔的值來建立網格,如第2-5行所示。使用網格經過調用Sigmoid類中的error函數來計算這些值的偏差(第5行)SN。在第8行建立軸手柄以建立三維繪圖。

爲了建立3D繪圖,使用ax.plot_surface函數,經過設置rstride和cstride,指定採樣點和數據的頻率,建立關於權重和偏差的表面圖。接下來,使用ax.contourf函數,經過將偏差值指定爲「 Z」方向(第9-10行),在表面頂部繪製相對於權重和誤差的偏差輪廓。在11-16行中,爲每一個軸設置標籤,併爲全部三維設置軸限。正在繪製三維繪圖,因此須要定義視點。在第17–18行中爲繪圖設置了一個視點,該視點在「 z」軸上的高度爲25度,距離爲12個單位。

def plot_animate_3d(i):

i = int(i*(epochs/animation_frames))

line1.set_data(sn.w_h[:i+1], sn.b_h[:i+1])

line1.set_3d_properties(sn.e_h[:i+1])

line2.set_data(sn.w_h[:i+1], sn.b_h[:i+1])

line2.set_3d_properties(np.zeros(i+1) - 1)

title.set_text('Epoch: {: d}, Error: {:.4f}'.format(i, sn.e_h[i]))

return line1, line2, title

if plot_3d:

#animation plots of gradient descent

i = 0

line1, = ax.plot(sn.w_h[:i+1], sn.b_h[:i+1], sn.e_h[:i+1], color='black',marker='.')

line2, = ax.plot(sn.w_h[:i+1], sn.b_h[:i+1], np.zeros(i+1) - 1, color='red', marker='.')

anim = animation.FuncAnimation(fig, func=plot_animate_3d, frames=animation_frames)

rc('animation', html='jshtml')

anim

基於靜態三維繪圖,想要可視化該算法的動態操做,該操做是由用於參數和偏差函的歷史變量在算法的各個時期捕獲。要建立梯度降低算法的動畫,將使用經過傳遞自定義函數plot_animate_3d做爲參數之一的animation.FuncAnimation函數,並指定建立動畫所需的幀數。plot_animate_3d函數plot_animate_3d爲「 w」和「 b」的相應值更新參數值和偏差值。在第7行的相同函數中,將文本設置爲顯示該特定時期的偏差值。最後,爲了在線顯示動畫,調用rc函數以在jupyter筆記本中呈現HTML內容。

相似於三維繪圖,能夠建立一個函數用以繪製二維等高線圖。

if plot_2d:

W = np.linspace(w_min, w_max, 256)

b = np.linspace(b_min, b_max, 256)

WW, BB = np.meshgrid(W, b)

Z = sn.error(X, Y, WW, BB)

fig = plt.figure(dpi=100)

ax = plt.subplot(111)

ax.set_xlabel('w')

ax.set_xlim(w_min - 1, w_max + 1)

ax.set_ylabel('b')

ax.set_ylim(b_min - 1, b_max + 1)

title = ax.set_title('Epoch 0')

cset = plt.contourf(WW, BB, Z, 25, alpha=0.8, cmap=cm.bwr)

plt.savefig("temp.jpg",dpi = 2000)

plt.show()

def plot_animate_2d(i):

i = int(i*(epochs/animation_frames))

line.set_data(sn.w_h[:i+1], sn.b_h[:i+1])

title.set_text('Epoch: {: d}, Error: {:.4f}'.format(i, sn.e_h[i]))

return line, title

if plot_2d:

i = 0

line, = ax.plot(sn.w_h[:i+1], sn.b_h[:i+1], color='black',marker='.')

anim = animation.FuncAnimation(fig, func=plot_animate_2d, frames=animation_frames)

rc('animation', html='jshtml')

anim

算法的實現

本節將實現梯度降低算法的不一樣變體,並生成三維和二維動畫圖。

Vanilla梯度降低

梯度降低算法是經過向相對於網絡參數的目標函數梯度的相反方向移動來更新參數。

參數更新規則由下式給出:

梯度降低更新規則:

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

self.w -= eta * dw / X.shape[0]

self.b -= eta * db / X.shape[0]

self.append_log()

在批量梯度降低中,迭代全部訓練數據點,並計算參數「 w」和「 b」的梯度累積和。而後根據累積梯度值和學習率更新參數值。

要執行梯度降低算法,請以下所示更改配置設置。

X = np.asarray([0.5, 2.5])

Y = np.asarray([0.2, 0.9])

algo = 'GD'

w_init = -2

b_init = -2

w_min = -7

w_max = 5

b_min = -7

b_max = 5

epochs = 1000

eta = 1

animation_frames = 20

plot_2d = True

plot_3d = True

在配置設置中,設置變量algo 爲‘GD’,代表在sigmoid神經元中執行vanilla梯度降低算法,以便找到最佳參數值。設置好配置參數後,將繼續執行SN類「fit」法,訓練小型數據上的sigmoid神經元。

梯度降低的歷史

上圖顯示了在算法學習最佳參數的同時,偏差、權重和誤差的歷史值在不一樣階段之間的變化方式。圖中須要注意的關鍵一點是,在初始階段,偏差值徘徊在0.5左右,但在200個階段後,偏差幾乎達到零。

若是想要繪製三維或二維動畫,則能夠設置布爾變量plot_2d和 plot_3d。展現三維偏差面在對應值「w」和「b」下的外觀。學習算法的目標是向偏差/損失最小的深藍色區域移動。

爲了可視化動態執行的算法,可使用函數plot_animate_3d生成動畫。播放動畫時,能夠看到該階段的編號和相應的偏差值。

若是想要放慢動畫的速度,能夠經過單擊視頻控件中的減號來實現,如上動畫所示。一樣,能夠爲二維等高線圖生成動畫,以查看算法如何向全局最小值移動。

基於Momentum的梯度降低

在Momentum GD中,以先前梯度和當前梯度指數衰減的累積平均值移動。

Momentum GD的代碼以下:

v_w, v_b = 0, 0

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

v_w = gamma * v_w + eta * dw

v_b = gamma * v_b + eta * db

self.w = self.w - v_w

self.b = self.b - v_b

self.append_log()

基於Momentum GD,涵蓋了歷史變量,以便跟蹤先前的梯度值。變量gamma表示須要給算法施加多少Momentum。變量v_w和 v_b用來計算基於歷史記錄和當前梯度的運動。在每一個階段結束時,調用append_log函數來存儲參數和損失函數值的歷史記錄。

爲sigmoid神經元執行Momentum GD,須要修改配置設置,以下所示:

X = np.asarray([0.5, 2.5])

Y = np.asarray([0.2, 0.9])

algo = 'Momentum'

w_init = -2

b_init = -2

w_min = -7

w_max = 5

b_min = -7

b_max = 5

epochs = 1000

mini_batch_size = 6

gamma = 0.9

eta = 1

animation_frames = 20

plot_2d = True

plot_3d = True

變量algo被設置爲「Momentum」,以示想要使用Momentum GD爲sigmoid神經元找到最佳參數;另外一個重要的變化是gamma變量,該變量用於控制在學習算法中Momentum的所需量。Gamma值在0-1之間變化。設置好配置參數後,將繼續執行SN類「 fit」法來訓練toy數據上的sigmoid神經元。

Momentum GD的變化

由圖可見,累積的歷史Momentum GD在極小值內外波動,權重和誤差項的值也出現了一些波動。

Nesterov加速梯度降低

在Nesterov加速梯度降低過程當中,但願在根據當前梯度值採起另外一步驟以前,瞭解是否接近最小值,從而避免出現過沖問題。

Momentum GD的代碼以下:

v_w, v_b = 0, 0

for i in range(epochs):

dw, db = 0, 0

v_w = gamma * v_w

v_b = gamma * v_b

for x, y in zip(X, Y):

dw += self.grad_w(x, y, self.w - v_w, self.b - v_b)

db += self.grad_b(x, y, self.w - v_w, self.b - v_b)

v_w = v_w + eta * dw

v_b = v_b + eta * db

self.w = self.w - v_w

self.b = self.b - v_b

self.append_log()

NAG GD代碼的主要變化是v_w和 v_b的計算。在Momentum GD中,一步完成這些變量的計算,但在NAG中,分兩個步驟進行計算。

v_w = gamma * v_w

v_b = gamma * v_b

for x, y in zip(X, Y):

dw += self.grad_w(x, y, self.w - v_w, self.b - v_b)

db += self.grad_b(x, y, self.w - v_w, self.b - v_b)

v_w = v_w + eta * dw

v_b = v_b + eta * db

第一部分中,在遍歷數據以前,將gamma與歷史變量相乘,而後使用self.w和 self.b中減去的歷史值來計算梯度。只須要設置algo變量爲「NAG」。能夠生成三維或二維動畫,以查看NAG GD與Momentum GD在達到全局最小值方面有何差別。

Mini-Batch and Stochastic梯度降低

無需一次查看全部數據點,將整個數據分爲多個子集。針對數據的每一個子集,計算子集中存在的每一個點的導數,並更新參數。不存在針對損失函數計算整個數據的導數,而是將其近似爲更少的點或較小的mini-batch size。這種批量計算梯度的方法稱爲 「 Mini-Batch 梯度降低」。

Mini-Batch GD的代碼以下所示:

for i in range(epochs):

dw, db = 0, 0

points_seen = 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

points_seen += 1

if points_seen % mini_batch_size == 0:

self.w -= eta * dw / mini_batch_size

self.b -= eta * db / mini_batch_size

self.append_log()

dw, db = 0, 0

在Mini Batch中,遍歷整個數據並使用變量points_seen跟蹤已看到的點數。若是看到的點數是mini-batch size 的倍數,那麼是正在更新sigmoid神經元的參數。在特殊狀況下,當mini-batch size等於1時,它將成爲隨機梯度降低。要執行Mini-Batch GD,只須要將算法變量設置爲「MiniBatch」。能夠生成3D或2D動畫,以瞭解Mini-Batch GD在達到全局最小值方面與Momentum GD有何差別。

AdaGrad梯度降低

AdaGrad隱藏的主要動機是針對數據集中不一樣特徵的自適應學習率,即不是針對數據集中全部特徵,使用相同的學習率,而是不一樣特徵採用不一樣學習率。

Adagrad的代碼以下所示:

v_w, v_b = 0, 0

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

v_w += dw**2

v_b += db**2

self.w -= (eta / np.sqrt(v_w) + eps) * dw

self.b -= (eta / np.sqrt(v_b) + eps) * db

self.append_log()

在Adagrad中,保持梯度的平方和,而後將學習率除以歷史值的平方根更新參數。這裏並不是靜態學習,而是密集和稀疏型的動態學習。生成圖/動畫的機制與上文相同。此處的想法是使用不一樣的toy數據集和不一樣的超參數配置。

RMSProp梯度降低

在RMSProp中,不一樣於AdaGrad中的梯度總和,梯度歷史是根據指數衰減的平均值計算的,這有助於防止密集型的分母快速增加。

RMSProp的代碼以下所示:

v_w, v_b = 0, 0

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw += self.grad_w(x, y)

db += self.grad_b(x, y)

v_w = beta * v_w + (1 - beta) * dw**2

v_b = beta * v_b + (1 - beta) * db**2

self.w -= (eta / np.sqrt(v_w) + eps) * dw

self.b -= (eta / np.sqrt(v_b) + eps) * db

self.append_log()

在AdaGrad代碼中惟一的更改是更新變量v_w和 v_b的方式。在AdaGrad中,v_w和v_b,從第一階段開始,老是按每一個參數的梯度平方遞增,但在RMSProp 中,v_w和 v_b是使用「gamma」的超參數指數衰減的梯度加權和。要執行RMSProp GD,只需將algo變量設置爲「RMSProp」。能夠生成3D或2D動畫,以查看RMSProp GD在達到全局最小值方面與 AdaGrad GD有何差別。

Adam梯度降低

Adam 擁有兩個歷史記錄,「mₜ」和Momentum GD中使用的歷史相似,「vₜ」和RMSProp中使用的歷史相似。

在運做中,Adam執行誤差校訂。它對「mₜ」和「vₜ」使用如下等式:

誤差校訂

誤差校訂可確保在訓練開始時不會出現怪異的行爲。Adam的要點是,它結合了Momentum GD(在溫和地區移動更快)和RMSProp GD(調整學習率)的優點。

Adam GD的代碼以下所示:

v_w, v_b = 0, 0

m_w, m_b = 0, 0

num_updates = 0

for i in range(epochs):

dw, db = 0, 0

for x, y in zip(X, Y):

dw = self.grad_w(x, y)

db = self.grad_b(x, y)

num_updates += 1

m_w = beta1 * m_w + (1-beta1) * dw

m_b = beta1 * m_b + (1-beta1) * db

v_w = beta2 * v_w + (1-beta2) * dw**2

v_b = beta2 * v_b + (1-beta2) * db**2

m_w_c = m_w / (1 - np.power(beta1, num_updates))

m_b_c = m_b / (1 - np.power(beta1, num_updates))

v_w_c = v_w / (1 - np.power(beta2, num_updates))

v_b_c = v_b / (1 - np.power(beta2, num_updates))

self.w -= (eta / np.sqrt(v_w_c) + eps) * m_w_c

self.b -= (eta / np.sqrt(v_b_c) + eps) * m_b_c

self.append_log()

在Adam優化器中,計算m_w & m_b來跟蹤momentum 歷史,並計算v_w & v_b以衰減分母並阻止其快速增加,就像在RMSProp中同樣。

以後,對基於Momentum和RMSProp的歷史變量實施誤差校訂。一旦計算出參數「 w」和「 b」的校訂值,將使用這些值來更新參數值。

執行Adam梯度降低算法,請以下所示更改配置設置。

X = np.asarray([3.5, 0.35, 3.2, -2.0, 1.5, -0.5])

Y = np.asarray([0.5, 0.50, 0.5, 0.5, 0.1, 0.3])

algo = 'Adam'

w_init = -6

b_init = 4.0

w_min = -7

w_max = 5

b_min = -7

b_max = 5

epochs = 200

gamma = 0.9

eta = 0.5

eps = 1e-8

animation_frames = 20

plot_2d = True

plot_3d = False

變量algo被設置爲「Adam」,表示使用Adam GD爲sigmoid神經元找到最佳參數;另外一個重要的變化是gamma 變量,該變量用於控制學習算法所需的momentum。Gamma值在0-1之間變化。設置配置參數後,將繼續執行SN類「 fit」法以訓練toy數據上的sigmoid神經元。

Adam GD中的參數變化

建立2D等高線動畫,該動畫顯示Adam GD學習通向全局極小值的路徑的方式。

Adam GD動畫

不一樣於RMSProp案例,沒有太多波動。尤爲在最初幾個階段以後,更加肯定地朝着最小值移動。

關於如何使用Numpy實現優化技術的討論到此結束。

實踐學習

本文中介紹了不一樣的狀況,使用了帶有靜態初始化點的toy數據集。可是可使用不一樣的初始化點,並針對每一個初始化點,使用不一樣的算法,看看在超參數中須要進行何種調整。本文討論的所有代碼都在GitHub存儲庫中。隨意分類或下載。最棒的是,能夠直接在google colab中運行代碼,而沒必要擔憂安裝軟件包。

https://github.com/Niranjankumar-c/GradientDescent_Implementation?source=post_page-----809e7ab3bab4----------------------

綜上所述,本文介紹瞭如何經過採起簡單的sigmoid神經元實現梯度算法的不一樣變種。此外,還了解了如何爲每一個變體(顯示學習算法如何找到最佳參數)建立精美的3D或2D動畫。

留言 點贊 關注

咱們一塊兒分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 「讀芯術」


(添加小編微信:dxsxbb,加入讀者圈,一塊兒討論最新鮮的人工智能科技哦~)

相關文章
相關標籤/搜索