入門神經(jīng)網(wǎng)絡(luò):梯度下降

姓名:王懷帥? 學(xué)號:16040410035

轉(zhuǎn)載自:http://www.itdecent.cn/p/27ce7c93b2d0=有修改

【嵌牛導(dǎo)讀】:梯度下降是機(jī)器學(xué)習(xí)中較為基本也比較常見的一類優(yōu)化算法的總稱。

【嵌牛鼻子】:度量錯誤、批量梯度下降、其他梯度下降

【嵌牛提問】:如何通過sigmoid函數(shù)、鏈?zhǔn)角髮?dǎo)法則以及基礎(chǔ)的矩陣乘法來研究梯度下降?

【嵌牛正文】:

度量錯誤

梯度下降是一種從“錯誤”中學(xué)習(xí)的算法。你也許意識到我們需要找到一種度量預(yù)測的錯誤程度的方法(metric)。通常情況下我們會選擇均方誤差(MSE),但也有一些其他的選擇,比如誤差平方和(SSR)或是平均絕對誤差(MAE)。文中統(tǒng)一使用均方誤差。

均方誤差

圖中的y以及y_hat的上角標(biāo)μ指代的是訓(xùn)練數(shù)據(jù)集中第μ個數(shù)據(jù),而非表示冪乘。

Google 和 Wikipedia 永遠(yuǎn)是最好的幫手,如果你想權(quán)衡使用 MSE 和 MAE 的利弊,我推薦你自己去探索一下。之前在StackExchange上看到過一個相關(guān)的問題,留在這里供你參考。一言以蔽之,MSE 對偏離實際值越多的預(yù)測值“懲罰”的越多(你想想,都給誤差值平方了),有利于我們的模型更好的趨近最優(yōu)情況。

這里需要插一句,梯度下降有很多不同的變種(稍后討論),我們上面中給出的均方誤差公式和接下來的算法,是對應(yīng)批量梯度下降法(Batch Gradient Descent,簡稱BGD)的,這是梯度下降法最原始的形式,它的具體思路是在更新每一參數(shù)時都使用所有的樣本來進(jìn)行更新。我們將繼續(xù)使用 sigmoid 函數(shù)作為激活函數(shù)。

Sigmoid 函數(shù)

Sigmoid 函數(shù)的導(dǎo)數(shù)

我們先給出從 Udacity 深度學(xué)習(xí)課程中截取的算法描述,我們進(jìn)行逐步分析這個算法的實現(xiàn)。

批量梯度下降

預(yù)設(shè):

這一部分沒有寫在上圖的算法中,但是是不可缺少的。我們需要初始化一些參數(shù)。分別為訓(xùn)練次數(shù)e學(xué)習(xí)率(learning rate)η預(yù)設(shè)權(quán)重(weight)w。關(guān)于預(yù)設(shè)權(quán)重的設(shè)定,請參考下面這段話。

First, you'll need to initialize the weights. We want these to be small such that the input to the sigmoid is in the linear region near 0 and not squashed at the high and low ends. It's also important to initialize them randomly so that they all have different starting values and diverge, breaking symmetry. So, we'll initialize the weights from a normal distribution centered at 0. A good value for the scale is 1/√

?n where n is the number of input units. This keeps the input to the sigmoid low for increasing numbers of input units.

第一步將初始化變化的權(quán)重 Δw,這一步實際上是便于我們稍后將算法轉(zhuǎn)為代碼。接下來第二步,針對訓(xùn)練數(shù)據(jù)集中的每一組數(shù)據(jù)我們執(zhí)行以下三個小步驟 (公式已略去,參見上圖):

將數(shù)據(jù)集在神經(jīng)網(wǎng)絡(luò)中進(jìn)行一次正向傳遞,得到預(yù)測結(jié)果y_hat

計算輸出層神經(jīng)元的誤差梯度(error gradient)δ

更新權(quán)重變化Δw_i

在完成了一次對整個數(shù)據(jù)集的遍歷之后,我們將進(jìn)行第三步,將Δw_i (權(quán)重變化值)w_i (預(yù)設(shè)的權(quán)重)相加,得到新的w_i。 這樣,我們便完成了一次對權(quán)重的更新。之后我們只需要重復(fù)e次第二、三步。

梯度下降的整個過程可以用下圖來進(jìn)行理解。最開始我們預(yù)設(shè)的權(quán)重在最外側(cè)深紅色圓環(huán)上,經(jīng)過一次一次的迭代逐漸靠近中心的最優(yōu)點(optima)。

梯度下降過程的可視化

接下來我們來一起構(gòu)建一個 Python 完成的梯度下降算法。完整的數(shù)據(jù)和代碼可以在我的GitHub Repo找到,這里就不貼出數(shù)據(jù)和準(zhǔn)備數(shù)據(jù)的代碼了。

import numpy as np

from data_prep import features, targets, features_test, targets_test

def sigmoid(x):

"""Calculate sigmoid"""

return 1 / (1 + np.exp(-x))

np.random.seed(42)

n_records, n_features = features.shape

last_loss = None

# 預(yù)設(shè)權(quán)重

weights = np.random.normal(scale=1 / n_features ** .5, size=n_features)

# 設(shè)定循環(huán)次數(shù)和學(xué)習(xí)率

epochs = 1000

learnrate = 0.5

for e in range(epochs):

# 第一步,設(shè)定預(yù)設(shè)變化的權(quán)重為0

del_w = np.zeros(weights.shape)

# 遍歷全部數(shù)據(jù)集

for x, y in zip(features.values, targets):

# 正向傳遞計算y_hat

output = sigmoid(np.dot(weights, x))

# 計算誤差梯度

error = (y - output) * output * (1 - output)

# 更新權(quán)重變化

del_w += error * x

# 對預(yù)設(shè)權(quán)重的更新

weights += learnrate * del_w / n_records

# 打印出運算過程的一些數(shù)據(jù)

if e % (epochs / 10) == 0:

out = sigmoid(np.dot(features, weights))

loss = np.mean((out - targets) ** 2)

if last_loss and last_loss < loss:

print("Train loss: ", loss, "? WARNING - Loss Increasing")

else:

print("Train loss: ", loss)

last_loss = loss

# 驗證我們的算法,在測試數(shù)據(jù)上進(jìn)行測試

tes_out = sigmoid(np.dot(features_test, weights))

predictions = tes_out > 0.5

accuracy = np.mean(predictions == targets_test)

print("Prediction accuracy: {:.3f}".format(accuracy))

如果你對第三步中更新預(yù)設(shè)權(quán)重的部分有疑惑,這里有一行代碼需要你額外注意,

# 對預(yù)設(shè)權(quán)重的更新

weights += learnrate * del_w / n_records

由于我們是將所有訓(xùn)練數(shù)據(jù)都遍歷了一遍之后得到的變化權(quán)重del_w, 所以需要將它除以訓(xùn)練數(shù)據(jù)集的數(shù)量。這也是和我們即將提到的另一種算法有差異的部分。

其他梯度下降方法

可以從參考資料的第一篇文章中得知,除了批量梯度下降法(Batch Gradient Descent,簡稱BGD)外,還有隨機(jī)梯度下降法(Stochastic Gradient Descent,簡稱SGD)以及更進(jìn)一步的小批量梯度下降法(Mini-batch Gradient Descent,簡稱MBGD)。這幾種不同方法的優(yōu)劣對比可以單開一篇文章來探討(或者參見參考資料第一篇),這里只通過介紹性的知識進(jìn)行簡單總結(jié)。

隨機(jī)梯度下降法和批量梯度下降法不同的是,在后者的訓(xùn)練過程中,每一次的訓(xùn)練都需要遍歷全部的訓(xùn)練數(shù)據(jù)集,這種算法的確可以保證達(dá)到全局最優(yōu)解(global optimal)。然而,如果我們的數(shù)據(jù)量較大,或者訓(xùn)練數(shù)據(jù)的維度較高(特征數(shù)量多)的時候,巨大的計算量會極大的拖慢我們模型的訓(xùn)練速度。所以這里提出一種改進(jìn)的算法——隨機(jī)梯度下降法。唯一一點和批量梯度下降法不同的是,我們每次選取一個訓(xùn)練數(shù)據(jù),計算誤差梯度后,直接在預(yù)設(shè)權(quán)重上進(jìn)行更新。這樣就避免了遍歷全部數(shù)據(jù)后再求平均變化權(quán)重的計算過程。極大的減少了計算量,對訓(xùn)練速度有著明顯的提高。美中不足的是,這種算法只能達(dá)到一個和全局最優(yōu)解極為接近的數(shù)值,而且不利于并行實現(xiàn)。

下面給出隨機(jī)梯度下降法的實現(xiàn)

import numpy as np

from data_prep import features, targets, features_test, targets_test

def sigmoid(x):

"""Calculate sigmoid"""

return 1 / (1 + np.exp(-x))

np.random.seed(42)

n_records, n_features = features.shape

last_loss = None

# 預(yù)設(shè)權(quán)重

weights = np.random.normal(scale=1 / n_features ** .5, size=n_features)

# 設(shè)定學(xué)習(xí)率

learnrate = 0.5

# 遍歷全部數(shù)據(jù)集

for x, y in zip(features.values, targets):

# 正向傳遞計算y_hat

output = sigmoid(np.dot(weights, x))

# 計算誤差梯度

error = (y - output) * output * (1 - output)

# 更新預(yù)設(shè)權(quán)重

weights += error * x

# 驗證我們的算法,在測試數(shù)據(jù)上進(jìn)行測試

tes_out = sigmoid(np.dot(features_test, weights))

predictions = tes_out > 0.5

accuracy = np.mean(predictions == targets_test)

print("Prediction accuracy: {:.3f}".format(accuracy))

可以看到,除了少去了整體循環(huán)的過程和更新權(quán)重的部分有變化,其余的地方并沒有太多改動過。

小批量梯度下降法(MBGD),是一種結(jié)合了以上兩種梯度下降法的新想法。其思路非常簡單,在 BGD 方法中,每次循環(huán)都將遍歷整個數(shù)據(jù)集,而在 SGD 方法中,沒有額外循環(huán),只遍歷每個數(shù)據(jù)一次即可。MBGD 則保留了 BGD 中循環(huán)的思路,但每次循環(huán)中并不會遍歷全部數(shù)據(jù),而是有選擇的隨機(jī)選取少量數(shù)據(jù)。具體的思路可以參考 Google。

BGDSGDMBGD

全局最優(yōu)是近似比SGD更接近最優(yōu)

訓(xùn)練速度很慢很快比SGD稍慢

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容