【Python】搭建你的第一個簡單的神經網路_準備篇_NN&DL學習筆記(二)
前言
本文為《Neural Network and Deep Learning》學習筆記(二),可以轉載但請標明原文地址。
本人剛剛入門、筆記簡陋不足、多有謬誤,而原書精妙易懂、不長篇幅常有柳暗花明之處,故推薦閱讀原書。
《Neural Network and Deep Learning》下載地址(中文版):Neural Network and Deep Learning(中文版)
注:這本書網上有很多免費版,隨便搜一下就有了,不用非得花積分下載我上傳的資料。
第二部分:準備篇(搭建神經網路、選擇學習演算法)
在理論篇中,我們講述了神經元與神經網路的基本知識,那麼下面我們就來搭建一個神經網路吧!
本篇中依然不涉及程式碼部分,只講解了一些前期準備過程,想要直接食用原始碼,可以跳到實踐篇。
我們將以【手寫數字識別】專案為例進行講解。
手寫數字識別是指:輸入一張圖片,圖片中包含一個數字,輸出該數字是什麼。
一、搭建一個三層神經網路
在理論篇中,我們講到:神經網路的架構可以分為三部分:輸入層、輸出層、隱藏層。下面我們就來分別設計:
1.1 設計輸入層(input layer)
輸入圖片,就相當於輸入圖片的每一個畫素。因此我們設計的網路的輸入層,必須包含給輸入畫素的值進行編碼的神經元。
例如,在手寫數字識別專案中,我們的輸入影象來源於MNIST資料集,這些影象是28×28大小的灰度影象。這意味著我們的輸入層需要包含784=28×28個輸入神經元,值為0.0表示白色,值為1.0表示黑色,中間數值表示逐漸暗淡的灰色。
這樣就完成了輸入層的設計。
1.2 設計輸出層(output layer)
我們需要的輸出是:“判斷輸入圖片是什麼數字”,一共有0-9共十個數字,因此我們的輸出神經元有10個,將它們按0-9編號。
接下來我們需要人為定義輸出值的意義:如果編號為0的輸出神經元被啟用,那麼表明輸出是“數字0”;如果編號為1的輸出神經元被啟用,那麼表明輸出是“數字1”;以此類推。
這裡出現了一個詞:“啟用”。還記得在理論篇中,我們曾經講過啟用函式嗎?啟用函式的作用在於:將神經元的輸入(x)對映到輸出(output),在這裡我們將output稱作啟用值。
我們共有10個輸出神經元,每個神經元都有一個output,也就是說都有一個啟用值。我們可以這樣定義:哪個輸出神經元輸出的啟用值最高,就證明網路判斷哪個數字最有可能。
比如:10個輸出神經元中,編號為0的神經元啟用值最高,那麼表明輸出是“數字0”.
這樣就完成了輸出層的設計及輸出值的解釋定義。
1.3 設計隱藏層(hidden layer)
作者曰:設計隱藏層是一門藝(xuan)術(xue)。
簡單起見,我們只設計一層隱藏層,假設該層中有n個隱藏神經元,我們將給n實驗不同的數值,觀察準確率的變化。
以上,三層神經網路設計完畢,網路拓撲圖如下所示:
二、設計學習演算法:梯度下降演算法
神經網路、機器學習,到底是怎麼學習的?!?!學習的到底是什麼?!?!
2.1 學習是什麼
讓我們再來看看我們的啟用函式(=S型函式)(=output的計算公式):
其中:x是輸入,output是輸出,權重w和偏置b是我們引入的引數。
問題來了:對於隨機輸入一張圖片x,如何使輸出output的準確率更高呢?
答案是:不斷調整引數w和b,使輸出值向著準確率更高的方向發展。
這就是學習過程,學習內容就是引數w和b,學習目的就是讓output準確率更高。
這就好比:我在藍翔開挖掘機,需要鏟一個雞蛋起來,我一鏟子下去往左偏了,那麼下次我就往右調整一點,我一鏟子下去力氣大了,那麼下次我就力氣小一點。我就這麼一次次調整引數,總有一天我能夠一鏟子下去就剷起雞蛋,這時候我會說:我學習到了最佳下鏟方向和最佳力氣,現在我鏟雞蛋的準確率非常高。
當然,在神經網路中,我們不可能一次次執行神經網路然後根據結果手動調整引數,於是我們需要設計學習演算法。
學習演算法的作用:讓網路自動調整權重w和偏置b,使模型向著準確率越來越高的方向發展。
在這裡我們介紹一種學習演算法:梯度下降演算法。
2.2 MNIST資料集
我們先來介紹一下MNIST資料集,MNIST 資料分為兩個部分:
第⼀部分包含 60,000 幅⽤於訓練資料的影象。這些影象掃描⾃250人的⼿寫樣本,這些影象是28 × 28 ⼤⼩的灰度影象。
第⼆部分包含 10,000 幅⽤於測試資料的影象,同樣是 28 × 28 的灰度影象,測試資料取⾃和訓練資料不同的另外⼀組 250人。
我們可以把第一部分的 60,000 副影象再劃分成兩個部分:
① ⼀部分 50,000 個影象作為訓練集,我們將⽤來訓練我們的神經⽹絡,使其學習引數w和b。
② 剩下的 10,000 個影象作為驗證集,在本文中我們沒有用到驗證集,但在之後的學習中我們會發現,它對於設定某些超引數很有用 —— 例如學習速率等。
第二部分的 10,000 副影象作為測試集,我們將⽤這些測試資料來評估我們的神經⽹絡準確性。
2.3 梯度下降演算法
1、什麼是代價函式/損失函式/loss
按照慣例,我們用x表示訓練輸入(訓練集影象的輸入),x是一個28×28=784維的向量,每個分量代表影象中單個畫素的灰度值。
我們用表示【輸入x】對應的【期望輸出y】,y是一個10維向量。
什麼叫【期望輸出】呢?說白了就是正確答案,比如:輸入一張圖片0,期望輸出就是,代表“只有編號為0的輸出神經元被激活了”。
我們希望有一個學習w和b的演算法,能夠讓我們的output與【期望輸出y】無限接近……等等,如何判斷output和【期望輸出y】的接近程度?
我們定義一個代價函式(損失函式/loss)來描述:“對於不同的w和b,output和【期望輸出y】的接近程度”
其中:w表示所有的網路中權重的集合,b是所有的偏置;
x是輸入,y(x)是對應x的期望輸出(也就是正確答案),a是對應x的實際輸出output;
n是訓練輸入資料的個數。
整個函式的意思是:對每個輸入x,計算一下期望值y和實際值a的差,平方後再求和,再除以2倍的總個數。
可以看出,C(w,b)≥0,而C(w,b)越接近0,證明期望值和實際值越接近,證明我們的神經網路準確率越高!
我們把C稱為二次代價函式,有時也稱為均方誤差或MSE。
到現在,我們的學習演算法目的已經非常明確了:找到合適的w和b,讓C越小越好!
2、梯度下降演算法
終於到正題了,再重複一遍,我們訓練神經網路的目的是,找到權重w和偏置b,最小化二次代價函式 C(w,b) 。
2.1 第一個目的:找到w和b,最小化C(w,b)
我們需要使用梯度下降演算法來達到這個目的,這裡需要一些導數的知識。
顯然,C是一個具有兩個變數的函式,我們給這兩個變數換個名字,v1和v2,那麼函式影象如下所示:
我們的目的現在變成:找到變數v1和v2,使函式C取最小值(儘量最小)。
2.2 第二個目的:找到變數v1和v2,最小化C(v1,v2)
梯度下降演算法的思想是:把我們的函式C想象成一個坑,假設把一個小球隨機放在某個位置,那麼小球總是會向低處滾,最終到達坑底。
這個過程的關鍵在於:“向低處滾”如何實現?
小球的位置可以用(v1,v2)描述,我們先來看看,當小球隨便移動時,函式C的值會有什麼變化:
(公式1)
這個公式的意思是:
假設小球原位置在(v1,v2),此時函式值是C;我們把小球移動到(v1*,v2*),此時函式值是C*;
令ΔC=C*-C;Δv1=v1*-v1;Δv2=v2*-v2;那麼我們可以通過Δv1和Δv2計算出ΔC,其中Δv1和Δv2的引數是偏導數,可以看作常量。
我們當然希望:小球每次移動,C越來越小,也就是C*<C,也就是ΔC<0。
我們的目的現在變成:選擇Δv1和Δv2,使ΔC<0
2.3 第三個目的:選擇Δv1和Δv2,使ΔC<0
2.3.1 簡化公式
我們需要將上面那個(公式1)簡化一下(就像簡化啟用函式的公式那樣):
① 定義Δv為v變化的變數:
② 定義,給它起個名字叫做梯度向量:
那麼上面那個(公式1)就簡化成下面這樣:
(公式2)
2.3.2 分析公式2
在(公式2)中,我們可以得到下面兩個資訊:
① 梯度向量的作用在於:對於v的變化,計算得到C的變化,就好像一個梯子把它們關聯起來,這就是被稱為“梯度向量”的原因。
② 我們的目的可以實現了!我們可以這麼選取Δv,使ΔC<0:
(規則1)
看上去是不是很簡單呢?代入上面那個公式2,就變成:
(公式3)
其中, 是個很小的正數,我們把它叫做學習速率。
又因為 肯定大於0,所以這樣計算得到的肯定小於0.
目標達成!
2.3.3 具體怎麼做呢?
挺過了公式推導,實現就簡單許多啦,我們只需要每次這樣做:
① 計算一下梯度向量
② 根據(規則1)計算一下
③ 表明:根據就可以得到v1和v2的變化。
所以,只要一直迭代上面三步,一直小於0,C就會越來越小、越來越小……
直到C已經不再減小,我們就得到了最好的v1和v2(就算不是最好,也是相當好的)。
總結一下,梯度下降演算法工作的方式就是重複計算梯度 ∇C,然後讓小球沿著相反的⽅向移動,沿著坑底“滾落”。我們可以想象它像這樣:
當然,求最小值的方法不僅僅有梯度下降法這一種,但有觀點認為這是最佳策略。理由在於:梯度下降法是在C下降最快的方向上,每次做微小移動。
2.3.4 學習速率
在開心之餘不要忘了還有一個問題:超引數【學習速率】該如何設定呢?
一方面,越小,我們越能夠逐步逼近全域性最低值,(公式2)的近似度越好;
另一方面,太小的話,梯度下降演算法又非常緩慢。
在真正的實踐中,通常是變化的,使近似度和速度得到折中。
我們將在實踐篇瞭解,設定不同的,對於準確率的影響有多麼巨大。
2.3.4 道理我都懂,但我們最初的目標:w和b怎麼沒出現呢?
我們需要把上面的梯度下降演算法應用到我們的神經網路中:
那麼,C(v1,v2)對應神經網路中的C(w,b);
(規則1)對應神經網路中的:
(規則2)
假設w和b是原引數,w*和b*是新引數,那麼新引數計算公式如下:
(公式4)
運用(公式4)來不斷更新我們的w和b,就可以讓神經網路學習了。
2.4 隨機梯度下降演算法
梯度下降演算法的缺點在於:需要計算,變數增多,計算量成平方倍的增大,導致學習時間增大,令人難以忍受。
因而出現了許多替代演算法,隨機梯度下降就是一種加速學習的演算法。
其思想在於:通過隨機選取小量訓練輸入樣本來計算,進而估算,減少計算量。
更準確地說,我們隨機選取小量的m個訓練輸入,標記為X1,X2,……,Xm,把它們稱為小批量資料。
假設m足夠大,我們可以用的平均值來估算。
而迭代公式也變成了下面這樣:
直到我們用完了所有的訓練輸入,被稱為完成了一個訓練迭代期。然後我們就會開始新一個迭代期。
需要注意的是,這相當於學習速率從 變成了 。
實踐證明,隨機梯度下降演算法能夠千倍加速學習過程。
神經網路架構已經設計好,學習演算法也已經選好,下一步,就該寫程式碼了。實踐篇,敬請期待。
【2018/11/19後記】
1、我真的瘋了,今天下午看到訪問量1w+,新建一篇部落格就開始碼字,全然不顧我還有一門考試、兩個報告、一個大作業、兩篇論文、一個專案要做……對CSDN真的是嘔心瀝血、真情實感了。
2、這篇從下午到晚上碼了將近三個小時,飯沒吃,晚課差點遲到,本來想一鼓作氣把實踐篇寫完,結果越寫越多、越寫越多,只能臨時加了個準備篇,實踐篇爭取今晚寫完,然後就真的要專心準備報告和考試了!!!立個flag,下週二之前不上部落格了!!!
3、第一次寫學習筆記,很粗糙,圖都是截自原書,有的公式懶得寫也直接截圖了,畢竟這種超級入門級的東西大概也沒多少人看,全理論也很難鑽研,我的講述又肯定比原書差一萬倍orz,只能聊以自慰吧,畢竟整理出來是真的很開心,感覺也收穫了很多。