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

上一篇傳送門

文章和代碼都在這兒, 歡迎Star GitHub repo

簡介

梯度下降是機器學習中較為基本也比較常見的一類優(yōu)化算法的總稱儡遮。在這里,我假設你已經(jīng)知道了什么是 sigmoid 函數(shù),掌握求導時的鏈式法則,和一些基礎的矩陣乘法碉渡。

如果你對以上三點有疑問的話,可以參考老朋友 Wikipedia 和 Google 給出的意見 灾测。

度量錯誤

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

均方誤差
均方誤差

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

Google 和 Wikipedia 永遠是最好的幫手等限,如果你想權衡使用 MSE 和 MAE 的利弊,我推薦你自己去探索一下芬膝。之前在 StackExchange 上看到過一個相關的問題望门,留在這里供你參考。一言以蔽之锰霜,MSE 對偏離實際值越多的預測值“懲罰”的越多(你想想筹误,都給誤差值平方了),有利于我們的模型更好的趨近最優(yōu)情況癣缅。關于 MSE 和 MAE 的介紹厨剪,也可以參考我之前的一篇文章

批量梯度下降

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

Sigmoid 函數(shù)
Sigmoid 函數(shù)
Sigmoid 函數(shù)的導數(shù)
Sigmoid 函數(shù)的導數(shù)

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


批量梯度下降
批量梯度下降

預設:
這一部分沒有寫在上圖的算法中儒士,但是是不可缺少的的止。我們需要初始化一些參數(shù)。分別為訓練次數(shù) e着撩,學習率(learning rate)η預設權重(weight)w诅福。關于預設權重的設定,請參考下面這段話拖叙。

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.

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

  • 將數(shù)據(jù)集在神經(jīng)網(wǎng)絡中進行一次正向傳遞(可參考我的上篇博客或 Google),得到預測結果 y_hat
  • 計算輸出層神經(jīng)元的誤差梯度(error gradient)δ
  • 更新權重變化 Δw_i

在完成了一次對整個數(shù)據(jù)集的遍歷之后挖滤,我們將進行第三步崩溪,將Δw_i (權重變化值)w_i (預設的權重)相加,得到新的 w_i斩松。 這樣伶唯,我們便完成了一次對權重的更新。之后我們只需要重復 e 次第二惧盹、三步乳幸。

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

梯度下降過程的可視化
梯度下降過程的可視化

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

哦對了,你可以試著更改預設部分提到的學習率和訓練次數(shù)秒际,看看它們會如何影響我們的訓練結果悬赏。

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

# 預設權重
weights = np.random.normal(scale=1 / n_features ** .5, size=n_features)

# 設定循環(huán)次數(shù)和學習率
epochs = 1000
learnrate = 0.5

for e in range(epochs):
    # 第一步,設定預設變化的權重為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)
        # 更新權重變化
        del_w += error * x
    
    # 對預設權重的更新
    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ù)上進行測試
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))

如果你對第三步中更新預設權重的部分有疑惑闽颇,這里有一行代碼需要你額外注意,

# 對預設權重的更新
weights += learnrate * del_w / n_records

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

其他梯度下降方法

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

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

下面給出隨機梯度下降法的實現(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

# 預設權重
weights = np.random.normal(scale=1 / n_features ** .5, size=n_features)

# 設定學習率
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)
    # 更新預設權重
    weights += error * x

# 驗證我們的算法科阎,在測試數(shù)據(jù)上進行測試
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)的過程和更新權重的部分有變化,其余的地方并沒有太多改動過锣笨。

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

BGD SGD MBGD
全局最優(yōu) 近似 比SGD更接近最優(yōu)
訓練速度 很慢 很快 比SGD稍慢

這塊有一點我記得不是非常清楚了挺身,希望有明白的朋友指點一下侯谁。忘記在哪本書里看到過SGD也可以達到全局最優(yōu)(也可能我記錯了)。

參考資料

獲取授權

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末墙贱,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子伍玖,更是在濱河造成了極大的恐慌嫩痰,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窍箍,死亡現(xiàn)場離奇詭異串纺,居然都是意外死亡,警方通過查閱死者的電腦和手機椰棘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門纺棺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人邪狞,你說我怎么就攤上這事祷蝌。” “怎么了帆卓?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵巨朦,是天一觀的道長。 經(jīng)常有香客問我剑令,道長糊啡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任吁津,我火速辦了婚禮棚蓄,結果婚禮上,老公的妹妹穿的比我還像新娘碍脏。我一直安慰自己梭依,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布典尾。 她就那樣靜靜地躺著役拴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪急黎。 梳的紋絲不亂的頭發(fā)上扎狱,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天侧到,我揣著相機與錄音,去河邊找鬼淤击。 笑死匠抗,一個胖子當著我的面吹牛,可吹牛的內容都是我干的污抬。 我是一名探鬼主播汞贸,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼印机!你這毒婦竟也來了矢腻?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤射赛,失蹤者是張志新(化名)和其女友劉穎多柑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楣责,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡竣灌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秆麸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片初嘹。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沮趣,靈堂內的尸體忽然破棺而出屯烦,到底是詐尸還是另有隱情,我是刑警寧澤房铭,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布驻龟,位于F島的核電站,受9級特大地震影響缸匪,放射性物質發(fā)生泄漏迅脐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一豪嗽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧豌骏,春花似錦龟梦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蒂窒,卻和暖如春躁倒,著一層夾襖步出監(jiān)牢的瞬間荞怒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工秧秉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留褐桌,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓象迎,卻偏偏與公主長得像荧嵌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子砾淌,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容