Theano深度學習結構分析


Reference:Theano入門三部曲

http://deeplearning.net/tutorial/logreg.html  (Softmax回歸)

http://deeplearning.net/tutorial/mlp.html (MLP多層感知器)

http://deeplearning.net/tutorial/lenet.html (簡易LeNet卷積神經網絡)

 

為什么要使用Theano?

深度學習最好使用一些庫,比如Theano。主要是因為反向傳播調整參數時,需要求導。鏈式求導本身沒有難處。

但是深度學習的神經網絡架構設計的比較復雜,層數又多(15層不是夢)。

在基本BP網絡的三層結構里,鏈式的長度已經到了5,推導公式已經不忍直視,人工求導顯然不是明智的。

Theano提供了grad梯度函數,自動根據表達式求一階導數,grad(cost,param),其中cost函數可以是一個超長超長的表達式。

param則可以是一個超大超大的數組或是矩陣。

顯然,有了grad函數,我們可以專心設計正向傳播的I/O,反向傳播只要一個grad函數即可。省去了復雜的公式推導。

 

Theano是深度學習較早的庫之一,由深度學習三大先驅(Geoffrey Hinton(Google)、Yann LeCun(Facebook))的Yoshua Bengio構建。

使用Python組織邏輯,C編譯執行,CUDA並行加速計算,是非常好的實驗平台。

它的庫源碼中包含大量注釋,並且提供深度學習的幾個基本模型的代碼實現文檔。

每篇文檔都采用paper的形式,集中了許多大牛的論文的精華、各種小trick,也給出了論文的具體引用,方便按圖索驥。

 

Theano的一般結構

Theano基於Python的面向對象,所以它的神經網絡也是基於面向對象的思路去寫的。

【對象】

它認為,淺層網絡的中分類器,深度網絡中的每個層,都是一個對象。

在這個對象里,你被指定了輸入格式,你只需要做兩件事:

根據格式,定義參數、定義輸出。

 

【數據讀入/處理】

從文件讀入數據,並且對數據進行全局分享處理(shared)

Theano中搞了一個奇怪的shared類型,Python的普通類型可以由theano.shared()方法轉換。

Shared區是供GPU、C代碼使用的內存區,與Python的內存區獨立,但是由Tensor變量聯系着。

這里就不得不提Theano的函數機制。theano.tensor中封裝的着大量的惰性函數。

這些惰性函數,在Python里是不會執行的。需要在theano.function()里執行。

theano.function()有四大區:

inputs=[], 如果只是一個普通的列表,就把輸入放在這個參數。如果輸入有很多,應該放在givens區里。inputs區不支持shared變量,所以也要挪到givens區。

inputs在寫function時基本是留空的,inputs=[],這個位置接受的是在線傳入的值,如果是離線值,應當放到givens區里。

 

outputs=普通函數or惰性函數,就是指定工作函數。

這里有個trick,就是如何print出Tensor表達式的量(因為該量的值只會在執行時確定,不能使用get_value)。以取出Softmax的預測值y_pred為例。

只要寫這樣一個function就行了,function(inputs=[],outputs=classifier.y_pred,givens={....自己指定范圍...})。

 

updates=參數更新的列表,格式[(原,新),(原,新)....],Shared區的變量只能在updates里更新,Python的中賦值只會讓變量留在Python的內存區。

但是在function的內存區和Python一點關系也每有。如果Python里設置一個Tensor關聯一些Shared變量的話,Shared區的updates會波及到Python區的值。

如CNN教程里的,params這個Tensor,明明在Python的全局內存區,但是每次update之后,都會被改變。

也就是說Shared區能影響Python區,但是Python區無法動Shread區一根汗毛。

givens={x:List1[:],y:List2[:],.....},其中x和y是outputs函數里使用的變量的名字,一定要對應,下面會講為什么。

 

theano.function()不是以Python的方式執行,而是迅速編譯成C代碼執行,相當於每個function都是一個獨立的子程序,所以這四大區是必要的。

由於是獨立子程序,Python中的普通變量顯然不能很好工作。所以一般都設成shared類型。

實際上,tensor的不少惰性函數都需要在Python狀態下的shared變量才能定義。原理未知。比如T.dot就不要求shared變量,但是grad的param一定要求是shared。

由於Theano的大部分計算都在function里,而function又是以C執行,所以Theano具有不輸於C的速度,同時兼具Python的靈活性。

 

【主過程:前向傳播構建&反向傳播迭代】

創建各個神經網絡層、分類器的實例對象,由I/O首尾相連,最后利用分類器構建cost函數,完成前向傳播。

利用各個層對象的參數、cost函數,構建梯度表達式,以及updates列表。

為訓練集、驗證集、測試集創建以theano.function()為殼的模型。

使用mini-batch梯度法分批訓練訓練集,測試驗證集&測試集。

 

【mini-batch梯度法與驗證集收斂】

深度學習中的梯度法應當使用mini-batch。

隨機梯度(Stochastic Gradient Descent)雖然快,但是不利於收斂。

批梯度(Batch Gradient Descent)太慢,但是收斂很好。

mini-batch做了個折中,它把數據集分成好多小batch,每個batch有統一的batchsize。

對小部分數據進行BGD,這樣兼顧了速度和收斂。

每個小batch即算一次iter迭代,做完全部batch,算一次epoch。

 

同時引入了驗證集,由原訓練集切割而成。驗證集在小數據集里不會出現。但是在大數據集里一定是要有的。

原因是大數據集的cost函數,你很難去評估什么值才算是勉強收斂。所以采用訓練、驗證交叉的方法替代傳統的看值收斂。

驗證集訓練法有幾個參數,patience(耐力)、patience_increase(耐力增長系數)、improvement_threshold(耐力增長(模型繼續迭代改善)閾值)

validation_frequency(驗證集評估頻率)、best_validation_loss(當前最低錯誤率)。

驗證集的算法:

while(epoch++)

     訓練每個小batch

         計算當前小batch的iter

         滿足評估頻率?開始評估!

         若評估loss<最好loss

             若評估loss<最好loss*閾值:patience=max(patience,iter*增長系數)

             更新最好loss

         (選擇):評估測試集

iter >=patience: 總迭代結束

 

一旦長時間評估loss沒有刷新patience,很快iter就會超過patience而結束迭代。

否則,則一直訓練,不停創造更好的loss。

        

           

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM