【面向代碼】學習 Deep Learning(二)Deep Belief Nets(DBNs)
http://blog.csdn.net/dark_scope/article/details/9447967
分類: 機器學習2013-07-24 11:50 517人閱讀 評論(5) 收藏 舉報
==========================================================================================
最近一直在看Deep Learning,各類博客、論文看得不少
但是說實話,這樣做有些疏於實現,一來呢自己的電腦也不是很好,二來呢我目前也沒能力自己去寫一個toolbox
只是跟着Andrew Ng的UFLDL tutorial 寫了些已有框架的代碼(這部分的代碼見github)
后來發現了一個matlab的Deep Learning的toolbox,發現其代碼很簡單,感覺比較適合用來學習算法
再一個就是matlab的實現可以省略掉很多數據結構的代碼,使算法思路非常清晰
所以我想在解讀這個toolbox的代碼的同時來鞏固自己學到的,同時也為下一步的實踐打好基礎
(本文只是從代碼的角度解讀算法,具體的算法理論步驟還是需要去看paper的
我會在文中給出一些相關的paper的名字,本文旨在梳理一下算法過程,不會深究算法原理和公式)
==========================================================================================
使用的代碼:DeepLearnToolbox ,下載地址:點擊打開,感謝該toolbox的作者
==========================================================================================
今天介紹DBN的內容,其中關鍵部分都是(Restricted Boltzmann Machines, RBM)的步驟,所以先放一張rbm的結構,幫助理解
(圖來自baidu的一個講解ppt)
==========================================================================================
照例,我們首先來看一個完整的DBN的例子程序:
這是\tests\test_example_DBN.m 中的ex2
[cpp] view plaincopy
- //train dbn
- dbn.sizes = [100 100];
- opts.numepochs = 1;
- opts.batchsize = 100;
- opts.momentum = 0;
- opts.alpha = 1;
- dbn =dbnsetup(dbn, train_x, opts); //here!!!
- dbn = dbntrain(dbn, train_x, opts); //here!!!
- //unfold dbn to nn
- nn = dbnunfoldtonn(dbn, 10); //here!!!
- nn.activation_function = 'sigm';
- //train nn
- opts.numepochs = 1;
- opts.batchsize = 100;
- nn = nntrain(nn, train_x, train_y, opts);
- [er, bad] = nntest(nn, test_x, test_y);
- assert(er < 0.10, 'Too big error');
其中的過程簡單清晰明了,就是dbnsetup(),dbntrain()以及dbnunfoldtonn()三個函數
最后fine tuning的時候用了(一)里看過的nntrain和nntest,參見(一)
\DBN\dbnsetup.m
這個實在沒什么好說的,
直接分層初始化每一層的rbm(受限波爾茲曼機(Restricted Boltzmann Machines, RBM))
同樣,W,b,c是參數,vW,vb,vc是更新時用到的與momentum的變量,見到代碼時再說
[cpp] view plaincopy
- for u = 1 : numel(dbn.sizes) - 1
- dbn.rbm{u}.alpha = opts.alpha;
- dbn.rbm{u}.momentum = opts.momentum;
- dbn.rbm{u}.W = zeros(dbn.sizes(u + 1), dbn.sizes(u));
- dbn.rbm{u}.vW = zeros(dbn.sizes(u + 1), dbn.sizes(u));
- dbn.rbm{u}.b = zeros(dbn.sizes(u), 1);
- dbn.rbm{u}.vb = zeros(dbn.sizes(u), 1);
- dbn.rbm{u}.c = zeros(dbn.sizes(u + 1), 1);
- dbn.rbm{u}.vc = zeros(dbn.sizes(u + 1), 1);
- end
\DBN\dbntrain.m
應為DBN基本就是把rbm當做磚塊搭建起來的,所以train也很簡單
[cpp] view plaincopy
- function dbn = dbntrain(dbn, x, opts)
- n = numel(dbn.rbm);
- //對每一層的rbm進行訓練
- dbn.rbm{1} = rbmtrain(dbn.rbm{1}, x, opts);
- for i = 2 : n
- x = rbmup(dbn.rbm{i - 1}, x);
- dbn.rbm{i} = rbmtrain(dbn.rbm{i}, x, opts);
- end
- end
首先映入眼簾的是對第一層進行rbmtrain(),后面每一層在train之前用了rbmup,
rbmup其實就是簡單的一句sigm(repmat(rbm.c', size(x, 1), 1) + x * rbm.W');
也就是上面那張圖從v到h計算一次,公式是Wx+c
接下來是最關鍵的rbmtrain了:
\DBN\rbmtrain.m
代碼如下,說明都在注釋里
論文參考:【1】Learning Deep Architectures for AI 以及
【2】A Practical Guide to Training Restricted Boltzmann Machines
你可以和【1】里面的這段偽代碼對應一下
[cpp] view plaincopy
- for i = 1 : opts.numepochs //迭代次數
- kk = randperm(m);
- err = 0;
- for l = 1 : numbatches
- batch = x(kk((l - 1) * opts.batchsize + 1 : l * opts.batchsize), :);
- v1 = batch;
- h1 = sigmrnd(repmat(rbm.c', opts.batchsize, 1) + v1 * rbm.W'); //gibbs sampling的過程
- v2 = sigmrnd(repmat(rbm.b', opts.batchsize, 1) + h1 * rbm.W);
- h2 = sigmrnd(repmat(rbm.c', opts.batchsize, 1) + v2 * rbm.W');
- //Contrastive Divergence 的過程
- //這和《Learning Deep Architectures for AI》里面寫cd-1的那段pseudo code是一樣的
- c1 = h1' * v1;
- c2 = h2' * v2;
- //關於momentum,請參看Hinton的《A Practical Guide to Training Restricted Boltzmann Machines》
- //它的作用是記錄下以前的更新方向,並與現在的方向結合下,跟有可能加快學習的速度
- rbm.vW = rbm.momentum * rbm.vW + rbm.alpha * (c1 - c2) / opts.batchsize;
- rbm.vb = rbm.momentum * rbm.vb + rbm.alpha * sum(v1 - v2)' / opts.batchsize;
- rbm.vc = rbm.momentum * rbm.vc + rbm.alpha * sum(h1 - h2)' / opts.batchsize;
- //更新值
- rbm.W = rbm.W + rbm.vW;
- rbm.b = rbm.b + rbm.vb;
- rbm.c = rbm.c + rbm.vc;
- err = err + sum(sum((v1 - v2) .^ 2)) / opts.batchsize;
- end
- end
\DBN\dbnunfoldtonn.m
DBN的每一層訓練完成后自然還要把參數傳遞給一個大的NN,這就是這個函數的作用
[cpp] view plaincopy
- function nn = dbnunfoldtonn(dbn, outputsize)
- %DBNUNFOLDTONN Unfolds a DBN to a NN
- % outputsize是你的目標輸出label,比如在MINST就是10,DBN只負責學習feature
- % 或者說初始化Weight,是一個unsupervised learning,最后的supervised還得靠NN
- if(exist('outputsize','var'))
- size = [dbn.sizes outputsize];
- else
- size = [dbn.sizes];
- end
- nn = nnsetup(size);
- %把每一層展開后的Weight拿去初始化NN的Weight
- %注意dbn.rbm{i}.c拿去初始化了bias項的值
- for i = 1 : numel(dbn.rbm)
- nn.W{i} = [dbn.rbm{i}.c dbn.rbm{i}.W];
- end
- end
最后fine tuning就再訓練一下NN就可以了
總結
還是那句話,本文只是梳理一下學習路線,具體的東西還是要靠paper
dbn主要的關鍵就是rbm,推薦幾篇經典的文章吧,rbm可是Hinton的寶貝啊
其中涉及到MCMC,Contrastive divergence,感覺比Autoencoder難理解多了
[1] An Introduction to Restricted Boltzmann Machines
[2] Learning Deep Architectures for AI Bengio大作啊
[3] A Practical Guide to Training Restricted Boltzmann Machines 上面提到過,比較細致
[4] A learning Algorithm for Boltzmann Machines Hinton的
- 頂
- 0
- 踩
- 0
- 2樓 _嘔啞嘲哳 2013-07-28 12:35發表 [回復]
-
-
1. 圖模型上的區別就是有向與無向 具體在算法上是如何體現的呢
2. 這樣DBN就只是實現了用來初始化 后面的fine tuning和分類實現還是必須由NN/BP來實現- Re: Dark_Scope 2013-07-28 12:54發表 [回復]
-
-
回復Dan7291125:1.其實我也不是很了解,我目前只看了DBN,你可以看看這個,may help:http://www.sigvc.org/bbs/thread-524-1-1.html
2.是的,SAE其實也是這樣的
- 1樓 _嘔啞嘲哳 2013-07-28 10:44發表 [回復]
-
-
請問一下兩個問題:
1. DBN中每層rbm是單獨訓練疊加的 DBM中每層rbm不是獨立的,這是DBN和DBM的區別所在么?
2. DBN中的每層rbm單獨訓練,得到的參數用來直接初始化NN的參數 和 用RBM逐層非監督建立結構 再用NN進行監督調整其實是一個意思吧?- Re: Dark_Scope 2013-07-28 12:04發表 [回復]
-
-
回復Dan7291125:1.yeah,圖模型不一樣
2.初始化之后還要訓練NN來調整,叫做fine tuning,之前做的只是初始化參數值而已