棧式自動編碼器(Stacked AutoEncoder)


棧式自動編碼器(Stacked AutoEncoder)

起源:自動編碼器

單自動編碼器,充其量也就是個強化補丁版PCA,只用一次好不過癮。

於是Bengio等人在2007年的  Greedy Layer-Wise Training of Deep Networks 中,

仿照stacked RBM構成的DBN,提出Stacked AutoEncoder,為非監督學習在深度網絡的應用又添了猛將。

這里就不得不提  “逐層初始化”(Layer-wise Pre-training),目的是通過逐層非監督學習的預訓練,

來初始化深度網絡的參數,替代傳統的隨機小值方法。預訓練完畢后,利用訓練參數,再進行監督學習訓練。

 

Part I  原理

非監督學習網絡訓練方式和監督學習網絡的方式是相反的。

在監督學習網絡當中,各個Layer的參數W受制於輸出層的誤差函數,因而Layeri參數的梯度依賴於Layeri+1的梯度,形成了"一次迭代-更新全網絡"反向傳播。

但是在非監督學習中,各個Encoder的參數W只受制於當前層的輸入,因而可以訓練完Encoderi,把參數轉給Layeri,利用優勢參數傳播到Layeri+1,再開始訓練。

形成"全部迭代-更新單層"的新訓練方式。這樣,Layeri+1效益非常高,因為它吸收的是Layeri完全訓練奉獻出的精華Input。

 

 

Part II  代碼與實現

主要參考  http://deeplearning.net/tutorial/SdA.html

棧式機在構造函數中,構造出各個Layer、Encoder,並且存起來。

Theano在構建棧式機中,易錯點是Encoder、Layer的參數轉移。

我們知道,Python的列表有深淺拷貝一說。Theano所有被shared標記的變量都是淺拷貝。

因而首先有這樣的錯誤寫法:

def __init__(self,rng,input,n_in,n_out,layerSize):
      ......
      for i in xrange(len(layerSize)):
            ......
            da.W=hidenlayer.W
            da.bout=hidenlayer.b

然后你在外部為da做grad求梯度的時候就報錯了,提示說params和cost函數不符合。

這是因為cost函數的Tensor表達式在寫cost函數時就確定了,這時候da這個對象剛好構造完,因而Tensor表達式中的da.W是構造隨機值。

然后我們在da構造完了之后,手賤把da.W指向的內存改變了(淺拷貝相當於引用),這樣算出的grad根本就不對。

其實這樣寫反了,又改成了這樣

def __init__(self,rng,input,n_in,n_out,layerSize):
      ......
      for i in xrange(len(layerSize)):
            ......
            hidenlayer.W=da.W
            hidenlayer.b=da.bout

好吧,這樣不會報錯了,而且每訓練一個Encoder,用get_value查看Layer的值確實改變了。但是,訓練Encoderi+1的時候,怎么感覺沒效果?

其實是真的沒效果,因為Layeri的參數根本沒有傳播到Layeri+1去。

Theano采用Python、C雙內存區設計,在C代碼中訓練完Encoderi時,參數並沒有轉到Layeri中。但是我們明明建立了淺拷貝啊?

原來updates函數在C內存區中,根本沒有覺察到淺拷貝關系,因為它在Python內存區中。

正確做法是像教程這樣,在da構造時建立淺拷貝關系,當編譯成C代碼之后,所有Python對象要在C內存區重新構造,自然就在C內存區觸發了淺拷貝。

 da=dA(rng,layerInput,InputSize,self.layerSize[i],hidenlayer.W,hidenlayer.b)

 或者訓練完Encoderi,強制把Encoderi參數注入到C內存區的Layeri里。

updateModel=function(inputs=[],outputs=[],updates=[(....)],
updateModel()

Theano的寫法風格近似於函數式語言,對象、函數中全是數學模型。一旦構造完了之后,就無法顯式賦值。

所以,在Python非構造函數里為對象賦值是愚蠢的,效果僅限於Python內存區。但是大部分計算都在C內存區,所以需要updates手動把值打進C內存區。

updates是溝通兩區的橋梁,一旦發現Python內存區中有建立淺拷貝關系,就會把C內存區中值更新到Python內存區。(有利於Python中保存參數)

但是絕對不會自動把Python內存區值,更新到C內存區當中。(這點必須小心)

這種做法可以擴展到,監督訓練完之后,參數的保存與導入。


免責聲明!

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



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