深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-04-基于Python的LeNet之MLP
原文地址可以查看更多信息
本文主要參考于:Multilayer Perceptron?
python源代碼(github下載 CSDN免費下載)
本文主要介紹含有單隱層的MLP的建模及實現。建議在閱讀本博文之前,先看一下LR的實現。因為LR是簡化版的MLP。LR不含有單隱層,則其輸入層直接連接到輸出層。從何處可以看出LR是輸入層直接連接輸出層?借用上一博文的公式:P(Y=i|x,W,b)=softmaxi(Wx+b)。其中,x是輸入層,softmax是激活函數,P就是輸出層了。我們將其化簡并轉換為一般神經網絡表達式:f(x)=g(Wx+b),其中g就是激活函數,f(x)就是輸出層了。可見輸入層經過激活函數得到的結果就是輸出了。很簡單吧。
那么MLP的模型公式和LR又有什么不同呢?下面來看一下MLP的模型建立。
一、模型
從MLP的結構圖中可以看出輸入層與隱藏層全連接,然后,隱藏層與輸出層全連接。那么整體的函數映射就是 f:RD→RL ,其中 D 是輸入向量 x 的維度, L 是輸出向量 f(x) 的維度。用矩陣表示整個三層之間的關系如下:
f(x)=G(W(2)(S(W(1)x+b(1)))+b(2))
其中,b(1),b(2)分別是三層之間(輸入層與隱層、隱層與輸出層之間)的偏置向量;W(1),W(2)分別是三層之間的權值矩陣;而S,G是分別是三層之間的激活函數。
對于連接單隱層的的表達式h(x)=Φ(x)=S(W(1)x+b(1)),其激活函數S常用的有tanh(a)=(ea?e?a)(ea+e?a)和sigmoid(a)=1(1+e?a)函數。在這里,我們將使用tanh作為激活函數,因為它通常能更快的達到訓練目標。
對于連接輸出層的表達式o(x)=G(W(2)h(x)+b(2)),我們應該不是很陌生,就是在篇頭或上一篇博文中講到的LR的模型表達式,在那里面其激活函數用的是softmax,它可以用來多分類,那么在這里,G也是采用softmax多分類器來分類。
接下來就是訓練模型獲取最佳參數,我們這里仍然采用MSGD(批量隨機梯度下降法)方法。這里我們需要學習的參數為θ={W(2),b(2),W(1),b(1)}。同樣,對于用鏈式法則求梯度??/?θ,我們就用theano已經實現的T.grad()方法。
講到這里小伙伴們或許有疑問了:沒有代價函數怎么求梯度啊?也就是??/?θ中的?是什么啊?很簡單,就是和LR中的代價函數基本是一樣的(在后邊還會講到cost代價函數為什么是基本一樣而不是一樣),因為結構都是一樣的,我們同樣要處理的是對于手寫數字MNIST的識別。最小化方法也是采用負對數似然函數,所以這里的?一清二楚了吧,還不清楚的,可以翻看LR的(二、定義代價函數)。
二、MLP代碼實現
我們主要關注實現含單隱層的MLP(只要單隱層的實現了,多隱層的就是多實例化幾個隱層而已)。MLP的實現包括3部分:輸入層、隱層、輸出層。
第一層:輸入層就是我們直接的輸入數據x,將其直接輸入到第二層;?
第二層:隱層的功能是用tanh函數處理第一層的輸入數據,并將結果作為第三層的輸入數據。因此需要我們用代碼實現,即根據LR實現一個隱層類;?
第三層:輸出層的功能是將第二層的輸入數據經過softmax函數,然后進行分類輸出。因此和LR是一樣的,所以這里直接調用上一篇定義的LR類-LogisticRegression類。
先提前講一下隱層權值的初始化問題。在LR類中,權值矩陣初始化為0。然而在隱層中就不能再初始化為0了,而是依據激活函數從symmetric interval(對稱間隔)中均勻采樣。這樣初始化是為了確保在訓練早期,每一個神經元都可以向后傳播(upward)激活信息,向前傳播(backward )梯度數據。也就是說在這一層用到了梯度反向傳播,那么權值矩陣就不能初始化為0,不知道解釋的如何?原文:(This initialization ensures that, early in training, each neuron operates in a regime of its activation function where information can easily be propagated both upward (activations flowing from inputs to outputs) and backward (gradients flowing from outputs to inputs))。
那么具體的均勻采樣范圍是什么呢??
對于函數tanh來說,interval為:[?6fanin+fanout?????????√,6fanin+fanout?????????√],其中fanin是第(i?1)層的單元個數;fanout是第i層的單元個數。如果對應到本實驗,第(i?1)層就是輸入層,輸入層輸入數據是樣本數據,因此其單元個數是樣本數據的長度;第i層就是隱層,其單元個數是需要實例化時傳入的。具體的看下方代碼。
對于函數sigmoid來說,interval為:[?46fanin+fanout?????????√,46fanin+fanout?????????√]。?
?
可以從文獻Xavier10中獲取以上范圍的來因。是一個大牛寫的論文,如果能看懂也很牛。?
部分代碼:
根據HiddenLayer類計算完結果后,我們相當于計算了公式h(x)=Φ(x)=S(W(1)x+b(1)),下面我們需要計算公式o(x)=G(W(2)h(x)+b(2)),然后根據前文的分析,第二個公式就是我們之前實現的LR。因此,我們只需要將隱層的結果作為LR的輸入,即可實現MLP的功能。下面,我們來寫一下MLP的代碼:
<code class="hljs python has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MLP</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(object)</span>:</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''多層感知機是一個前饋人工神經網絡模型。它包含一個或多個隱層單元以及非線性激活函數。中間層通常使用tanh或sigmoid作為激活函數,頂層(輸出層)通常使用softmax作為分類器。'''</span><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">__init__</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(self, rng, input, n_in, n_hidden, n_out)</span>:</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''rng, input在前邊已經介紹過。n_in : int類型,輸入數據的數目,此處對應的是輸入的樣本數據。 n_hidden : int類型,隱層單元數目n_out : int類型,輸出層單元數目,此處對應的是輸入樣本的標簽數據的數目。 '''</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 首先定義一個隱層,用來連接輸入層和隱層。</span>self.hiddenLayer = HiddenLayer(rng=rng,input=input,n_in=n_in,n_out=n_hidden,activation=T.tanh)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 然后定義一個LR層,用來連接隱層和輸出層</span>self.logRegressionLayer = LR(input=self.hiddenLayer.output,n_in=n_hidden,n_out=n_out)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 規則化,常用的是L1和L2。是為了防止過擬合。</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 其計算方式很簡單。具體規則化的內容在文章下方詳細說一下</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># L1項的計算公式是:將W的每個元素的絕對值累加求和。此處有2個W,因此兩者相加。</span>self.L1 = (abs(self.hiddenLayer.W).sum()+ abs(self.logRegressionLayer.W).sum())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># L2項的計算公式是:將W的每個元素的平方累加求和。此處有2個W,因此兩者相加。</span>self.L2_sqr = ((self.hiddenLayer.W ** <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>).sum()+ (self.logRegressionLayer.W ** <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>).sum())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 和LR一樣,計算負對數似然函數,計算誤差。</span>self.negative_log_likelihood = (self.logRegressionLayer.negative_log_likelihood)self.errors = self.logRegressionLayer.errorsself.params = self.hiddenLayer.params + self.logRegressionLayer.paramsself.input = input</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li></ul> 現在就來解釋一下篇頭中提到的代價函數是基本一樣的原因。?
首先來說一下規則化。當我們訓練模型試圖讓它在面對新的輸入樣本時產生更好的結果(就是有更好的泛化能力),我們往往會采用梯度下降方法。而本實驗中用到的MSGD方法卻沒有考慮到一個問題,那就是過擬合現象。一旦出現過擬合,那么在面對新的樣本時很難有好的結果。為了控制過擬合,一個比較有效的方法就是規格化。就是給每個參數θ(對應于W中的每一個元素)增加一個懲罰項,如果某個參數的系數非常大那么θ就會接近于0了。那么什么是L1和L2規格化呢?下面看一個公式,假設我們的代價函數是:?
那么規則化后的代價函數就是:?
E(θ,D)=NLL(θ,D)+λR(θ)(R-2)
就是加入了一個 λR(θ) 。在我們的實驗中,具體的公式如下:?
E(θ,D)=NLL(θ,D)+λ||θ||pp(R-3)
其中:?
||θ||p=??∑j=0|θ||θj|p??1p(R-4)
不難發現,當把公式 (R?4) 帶入到公式 (R?3) 后, 1p 次方與 p 次方約掉,就剩下了:?
E(θ,D)=NLL(θ,D)+λ∑j=0|θ||θj|p(R-5)
(R?5) 就是 θ 的 Lp 項; λ 是一個很重的規則化參數。我們通常令 Lp 中的 p 取值為 1 或者 2 ,這就是命名為L1和L2的原因。
原則上,當代價函數中增添了規則化項之后會使得網絡擬合函數時更加平滑。所以,理論上,最小化NLL與R(θ)的和等價于在擬合訓練數據和找到一般性的解(分類超平面)之間找到最佳的權衡。根據Occam’s razor規則,最小化加入規則化項的公式會使得我們更容易找到擬合訓練數據的解(分類超平面)。
實際上一個模型有一個簡單的超平面解并不意味著它的泛化能力很好。實驗證明,含有這種規格化項的神經網絡的泛化能力更好,尤其是在比較小的數據集上。?
下面來看一下帶有規則化項的代價函數代碼如何寫:
最后就是參數求梯度以及參數更新,基本和LR的區別不大。訓練模型函數、測試模型函數、驗證模型函數和LR相同。至此,代碼實現基本告一段落,可以下載全部代碼運行測試。其他的代碼注釋不多,因為應該比較簡單。只有一個mlp.py文件。下載來,直接python mlp.py即可運行。如果有不懂的地方可以留言,也可以翻看上一篇LR的實現。本文所介紹的mlp去對mnist分類官方給出的一個結果是:
<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">Optimization complete. Best validation score <span class="hljs-operator" style="box-sizing: border-box;">of</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.690000</span> % obtained <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">at</span> iteration <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2070000</span>, <span class="hljs-operator" style="box-sizing: border-box;">with</span> test performance <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.650000</span> % The code <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">file</span> mlp.py ran <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">97.34</span>m</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>我也正在跑代碼,因為還是比較耗時的。這個網址里邊記錄了目前為止所做過的實驗以及結果。有興趣的可以看一下。最好的誤差能達到0.23%了,天呢,接近100%的識別率了。
參考目錄:?
1.?官方教程?
2.?Stanford機器學習—第三講. 邏輯回歸和過擬合問題的解決 logistic Regression & Regularization?
3.?深度學習(DL)與卷積神經網絡(CNN)學習筆記隨筆-03-基于Python的LeNet5之LR
總結
以上是生活随笔為你收集整理的深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-04-基于Python的LeNet之MLP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习(DL)与卷积神经网络(CNN)
- 下一篇: 深度学习(DL)与卷积神经网络(CNN)