深度学习Deep learning:四十九(RNN-RBM简单理解)
前言:
本文主要是bengio的deep learning tutorial教程主頁(yè)中最后一個(gè)sample:rnn-rbm in polyphonic music.?即用RNN-RBM來model復(fù)調(diào)音樂,訓(xùn)練過程中采用的是midi格式的音頻文件,接著用建好的model來產(chǎn)生復(fù)調(diào)音樂。對(duì)音樂建模的難點(diǎn)在與每首樂曲中幀間是高度時(shí)間相關(guān)的(這樣樣本的維度會(huì)很高),用普通的網(wǎng)絡(luò)模型是不能搞定的(普通設(shè)計(jì)網(wǎng)絡(luò)模型沒有考慮時(shí)間維度,圖模型中的HMM有這方面的能力),這種情況下可以采用RNN來處理,這里的RNN為recurrent neural network中文為循環(huán)神經(jīng)網(wǎng)絡(luò),另外還有一種RNN為recursive neural network翻為遞歸神經(jīng)網(wǎng)絡(luò)。本文中指的是循環(huán)神經(jīng)網(wǎng)絡(luò)。
?
RNN簡(jiǎn)單介紹:
首先來看RNN和普通的feed-forward網(wǎng)絡(luò)有什么不同。RNN的網(wǎng)絡(luò)框架如下:
?
由結(jié)構(gòu)圖可以知道,RNN和feed-forward相比只是中間隱含層多了一個(gè)循環(huán)的圈而已,這個(gè)圈表示上一次隱含層的輸出作為這一次隱含層的輸入,當(dāng)然此時(shí)的輸入是需要乘以一個(gè)權(quán)值矩陣的,這樣的話RNN模型參數(shù)只多了個(gè)權(quán)值矩陣。更形象的RNN圖可以參考:
?
以及圖:
?
按照上圖所示,可知道RNN網(wǎng)絡(luò)前向傳播過程中滿足下面的公式(參考文獻(xiàn)Learning Recurrent Neural Networks with Hessian-Free Optimization):
?
其代價(jià)函數(shù)可以是重構(gòu)的誤差:
?
也可以是交叉熵:
?
相信熟悉普通深究網(wǎng)絡(luò)的同學(xué)看懂這些應(yīng)該不難。
?
RNN-RBM簡(jiǎn)單介紹:
RNN-RBM來自ICML2012的論文:Modeling Temporal Dependencies in High-Dimensional Sequences: Application to Polyphonic Music Generation and Transcription,它由一個(gè)單層的RBM網(wǎng)絡(luò)和單層的RNN網(wǎng)絡(luò)構(gòu)成,且由RNN網(wǎng)絡(luò)的輸出作為最終網(wǎng)絡(luò)的輸出。RBM部分當(dāng)生成模型的功能,比如這里的音樂生成,RNN部分當(dāng)判別模型作用,比如它的輸出當(dāng)值可當(dāng)做提取的特征。RNN-RBM模型的結(jié)構(gòu)如下:
?
模型上面是RBM部分,下面是RNN部分,對(duì)應(yīng)的公式可以參考論文。模型中一共有9個(gè)參數(shù):
?
整個(gè)模型的代價(jià)函數(shù)為-P(v),其中:
?
對(duì)該loss function求導(dǎo),然后采用SGD算法就可以求出模型中的各個(gè)參數(shù)了。當(dāng)然了,其中的RBM部分還需要用Gibbs采樣完成CD-k算法。
?
實(shí)驗(yàn)結(jié)果:
實(shí)驗(yàn)部分參考http://deeplearning.net/tutorial/rnnrbm.html,實(shí)驗(yàn)須用的數(shù)據(jù)和paper對(duì)應(yīng)的見http://www-etud.iro.umontreal.ca/~boulanni/icml2012. 由于本人對(duì)樂理方面的知識(shí)不是很懂,很多實(shí)驗(yàn)代碼細(xì)節(jié)沒有去深究,只是看下算法的大概流程。由RNN-RBM生成的兩個(gè)pinao roll數(shù)據(jù)如下(程序跑了20個(gè)小時(shí)左右):?
?
迭代200次后的cost為:
...... Epoch 197/200 -4.7050858655 Epoch 198/200 -4.69198161366 Epoch 199/200 -4.66586797348 Epoch 200/200 -4.68651185036?
代碼如下:?
# Author: Nicolas Boulanger-Lewandowski # University of Montreal (2012) # RNN-RBM deep learning tutorial # More information at http://deeplearning.net/tutorial/rnnrbm.htmlimport glob import os import sysimport numpy try:import pylab except ImportError:print "pylab isn't available, if you use their fonctionality, it will crash"print "It can be installed with 'pip install -q Pillow'"from midi.utils import midiread, midiwrite import theano import theano.tensor as T from theano.tensor.shared_randomstreams import RandomStreams#Don't use a python long as this don't work on 32 bits computers. numpy.random.seed(0xbeef) rng = RandomStreams(seed=numpy.random.randint(1 << 30)) theano.config.warn.subtensor_merge_bug = False#給定rbm的3個(gè)參數(shù)w,bv,bh,輸入端數(shù)據(jù)v,以及gibbs采用長(zhǎng)度k #返回的tuple元素依次是:v_samples(k次gibbs采用得到的輸入端數(shù)據(jù),01化后的),cost(rbm模型中的-log(v)),monitor(監(jiān)控用變量), #updates(保留每次迭代的中間過程,如果是shared變量的話) def build_rbm(v, W, bv, bh, k):'''Construct a k-step Gibbs chain starting at v for an RBM.v : Theano vector or matrixIf a matrix, multiple chains will be run in parallel (batch). W : Theano matrixWeight matrix of the RBM. bv : Theano vectorVisible bias vector of the RBM. bh : Theano vectorHidden bias vector of the RBM. k : scalar or Theano scalarLength of the Gibbs chain.Return a (v_sample, cost, monitor, updates) tuple:v_sample : Theano vector or matrix with the same shape as `v`Corresponds to the generated sample(s). cost : Theano scalarExpression whose gradient with respect to W, bv, bh is the CD-k approximationto the log-likelihood of `v` (training example) under the RBM.The cost is averaged in the batch case. monitor: Theano scalarPseudo log-likelihood (also averaged in the batch case). updates: dictionary of Theano variable -> Theano variableThe `updates` object returned by scan.'''def gibbs_step(v): #該函數(shù)功能是一次gibbs采樣后得到的mean_v,vmean_h = T.nnet.sigmoid(T.dot(v, W) + bh)h = rng.binomial(size=mean_h.shape, n=1, p=mean_h, #產(chǎn)生二項(xiàng)分布,隱含層節(jié)點(diǎn)01化dtype=theano.config.floatX)mean_v = T.nnet.sigmoid(T.dot(h, W.T) + bv)v = rng.binomial(size=mean_v.shape, n=1, p=mean_v, #反向傳播,輸入層節(jié)點(diǎn)也01化dtype=theano.config.floatX)return mean_v, v #一次Gibbs采樣后輸入層01化前后的值#輸入的是v,輸出的是每一次Gibbs采樣后的v構(gòu)成的list,一共進(jìn)行k次Gibbs采樣chain, updates = theano.scan(lambda v: gibbs_step(v)[1], outputs_info=[v], n_steps=k) #updates里面裝的是每次的輸入值v_sample = chain[-1] #k次Gibbs采樣后輸入端的值(01化過后的) mean_v = gibbs_step(v_sample)[0] #再次Gibbs前進(jìn)一次,得到?jīng)]有01化的輸入端數(shù)碼,用于監(jiān)控的變量monitor = T.xlogx.xlogy0(v, mean_v) + T.xlogx.xlogy0(1 - v, 1 - mean_v)monitor = monitor.sum() / v.shape[0]def free_energy(v): #公式4,能量的計(jì)算公式return -(v * bv).sum() - T.log(1 + T.exp(T.dot(v, W) + bh)).sum()cost = (free_energy(v) - free_energy(v_sample)) / v.shape[0] #代價(jià)函數(shù)return v_sample, cost, monitor, updatesdef shared_normal(num_rows, num_cols, scale=1):'''Initialize a matrix shared variable with normally distributed elements.'''return theano.shared(numpy.random.normal(scale=scale, size=(num_rows, num_cols)).astype(theano.config.floatX))def shared_zeros(*shape):'''Initialize a vector shared variable with zero elements.'''return theano.shared(numpy.zeros(shape, dtype=theano.config.floatX))def build_rnnrbm(n_visible, n_hidden, n_hidden_recurrent):'''Construct a symbolic RNN-RBM and initialize parameters.n_visible : integerNumber of visible units. n_hidden : integerNumber of hidden units of the conditional RBMs. n_hidden_recurrent : integerNumber of hidden units of the RNN.Return a (v, v_sample, cost, monitor, params, updates_train, v_t,updates_generate) tuple:v : Theano matrixSymbolic variable holding an input sequence (used during training) v_sample : Theano matrixSymbolic variable holding the negative particles for CD log-likelihoodgradient estimation (used during training) cost : Theano scalarExpression whose gradient (considering v_sample constant) corresponds to theLL gradient of the RNN-RBM (used during training) monitor : Theano scalarFrame-level pseudo-likelihood (useful for monitoring during training) params : tuple of Theano shared variablesThe parameters of the model to be optimized during training. updates_train : dictionary of Theano variable -> Theano variableUpdate object that should be passed to theano.function when compiling thetraining function.v_t : Theano matrixSymbolic variable holding a generated sequence (used during sampling) updates_generate : dictionary of Theano variable -> Theano variableUpdate object that should be passed to theano.function when compiling thegeneration function.'''W = shared_normal(n_visible, n_hidden, 0.01)bv = shared_zeros(n_visible)bh = shared_zeros(n_hidden)Wuh = shared_normal(n_hidden_recurrent, n_hidden, 0.0001)Wuv = shared_normal(n_hidden_recurrent, n_visible, 0.0001)Wvu = shared_normal(n_visible, n_hidden_recurrent, 0.0001)Wuu = shared_normal(n_hidden_recurrent, n_hidden_recurrent, 0.0001)bu = shared_zeros(n_hidden_recurrent)params = W, bv, bh, Wuh, Wuv, Wvu, Wuu, bu # learned parameters as shared# variables v = T.matrix() # a training sequenceu0 = T.zeros((n_hidden_recurrent,)) # initial value for the RNN hidden# units# If `v_t` is given, deterministic recurrence to compute the variable# biases bv_t, bh_t at each time step. If `v_t` is None, same recurrence# but with a separate Gibbs chain at each time step to sample (generate)# from the RNN-RBM. The resulting sample v_t is returned in order to be# passed down to the sequence history.# 如果給定t時(shí)刻的v和t-1時(shí)刻的u,那么返回t時(shí)刻的u,bv,bh,含有25次Gibbs采樣過程# 如果只給定t-1時(shí)刻的u(即沒有t時(shí)刻的v),則表示的是由rbm來產(chǎn)生v了,所以這時(shí)候返回的是t時(shí)刻的v和u,以及# 迭代過程中輸入端的變換過程updatesdef recurrence(v_t, u_tm1):bv_t = bv + T.dot(u_tm1, Wuv)bh_t = bh + T.dot(u_tm1, Wuh)generate = v_t is Noneif generate:v_t, _, _, updates = build_rbm(T.zeros((n_visible,)), W, bv_t, #第一個(gè)參數(shù)應(yīng)該是v,因此這里的v是0bh_t, k=25)u_t = T.tanh(bu + T.dot(v_t, Wvu) + T.dot(u_tm1, Wuu))return ([v_t, u_t], updates) if generate else [u_t, bv_t, bh_t]# For training, the deterministic recurrence is used to compute all the# {bv_t, bh_t, 1 <= t <= T} given v. Conditional RBMs can then be trained# in batches using those parameters.(u_t, bv_t, bh_t), updates_train = theano.scan( #訓(xùn)練rbm過程的符號(hào)表達(dá)式(每次只包括25步的Gibbs采樣)lambda v_t, u_tm1, *_: recurrence(v_t, u_tm1),sequences=v, outputs_info=[u0, None, None], non_sequences=params)v_sample, cost, monitor, updates_rbm = build_rbm(v, W, bv_t[:], bh_t[:],k=15)updates_train.update(updates_rbm)# symbolic loop for sequence generation(v_t, u_t), updates_generate = theano.scan(lambda u_tm1, *_: recurrence(None, u_tm1),#進(jìn)行g(shù)enerate產(chǎn)生過程的符號(hào)表達(dá)式,迭代200次outputs_info=[None, u0], non_sequences=params, n_steps=200)return (v, v_sample, cost, monitor, params, updates_train, v_t, #cost在build_rbm()中產(chǎn)生 updates_generate)class RnnRbm: #兩個(gè)功能,訓(xùn)練RNN-RBM模型和用訓(xùn)練好的RNN-RBM模型來產(chǎn)生樣本'''Simple class to train an RNN-RBM from MIDI files and to generate sample sequences.'''def __init__(self, n_hidden=150, n_hidden_recurrent=100, lr=0.001, r=(21, 109), dt=0.3):'''Constructs and compiles Theano functions for training and sequence generation.n_hidden : integerNumber of hidden units of the conditional RBMs. n_hidden_recurrent : integerNumber of hidden units of the RNN. lr : floatLearning rate r : (integer, integer) tupleSpecifies the pitch range of the piano-roll in MIDI note numbers, includingr[0] but not r[1], such that r[1]-r[0] is the number of visible units of theRBM at a given time step. The default (21, 109) corresponds to the full rangeof piano (88 notes). dt : floatSampling period when converting the MIDI files into piano-rolls, orequivalently the time difference between consecutive time steps.'''self.r = rself.dt = dt(v, v_sample, cost, monitor, params, updates_train, v_t,updates_generate) = build_rnnrbm(r[1] - r[0], n_hidden, #在該函數(shù)里面有設(shè)置迭代次數(shù)等參數(shù) n_hidden_recurrent)gradient = T.grad(cost, params, consider_constant=[v_sample])updates_train.update(((p, p - lr * g) for p, g in zip(params,gradient))) #sgd算法,利用公式4的cost公式搞定8個(gè)參數(shù)的更新self.train_function = theano.function([v], monitor,updates=updates_train)self.generate_function = theano.function([], v_t, #updates_generate步驟在build_rnnrbm()中產(chǎn)生,音樂的產(chǎn)生主要在那函數(shù)中updates=updates_generate)def train(self, files, batch_size=100, num_epochs=200):'''Train the RNN-RBM via stochastic gradient descent (SGD) using MIDI files converted to piano-rolls.files : list of stringsList of MIDI files that will be loaded as piano-rolls for training. batch_size : integerTraining sequences will be split into subsequences of at most this sizebefore applying the SGD updates. num_epochs : integerNumber of epochs (pass over the training set) performed. The user cansafely interrupt training with Ctrl+C at any time.'''assert len(files) > 0, 'Training set is empty!' \' (did you download the data files?)'dataset = [midiread(f, self.r,self.dt).piano_roll.astype(theano.config.floatX)for f in files] #讀取midi文件try:for epoch in xrange(num_epochs): #訓(xùn)練200次numpy.random.shuffle(dataset) #將訓(xùn)練樣本打亂costs = []for s, sequence in enumerate(dataset): #返回的s是序號(hào),sequence是dataset對(duì)應(yīng)序號(hào)下的值for i in xrange(0, len(sequence), batch_size):cost = self.train_function(sequence[i:i + batch_size]) #train_function在init()函數(shù)中 costs.append(cost)print 'Epoch %i/%i' % (epoch + 1, num_epochs),print numpy.mean(costs) sys.stdout.flush()except KeyboardInterrupt:print 'Interrupted by user.'def generate(self, filename, show=True):'''Generate a sample sequence, plot the resulting piano-roll and save it as a MIDI file.filename : stringA MIDI file will be created at this location. show : booleanIf True, a piano-roll of the generated sequence will be shown.'''piano_roll = self.generate_function() #直接生成piano roll文件midiwrite(filename, piano_roll, self.r, self.dt)#將piano_roll文件轉(zhuǎn)換成midi文件并保存if show:extent = (0, self.dt * len(piano_roll)) + self.rpylab.figure()pylab.imshow(piano_roll.T, origin='lower', aspect='auto',interpolation='nearest', cmap=pylab.cm.gray_r,extent=extent)pylab.xlabel('time (s)')pylab.ylabel('MIDI note number')pylab.title('generated piano-roll')def test_rnnrbm(batch_size=100, num_epochs=200):model = RnnRbm()#os.path.dirname(__file__)為獲得當(dāng)前文件的目錄,os.path.split(path)是將path按照最后一個(gè)斜線分成父和子的部分re = os.path.join(os.path.split(os.path.dirname(__file__))[0], #該代碼完成的功能是,找到當(dāng)前文件的上級(jí)目錄下的/data/Nottinghan/train/*.mid文件'data', 'Nottingham', 'train', '*.mid') #re得到該目錄下的所有.mid文件model.train(glob.glob(re),#glob.glob()只是將文件路徑名等弄成linux的格式batch_size=batch_size, num_epochs=num_epochs)return modelif __name__ == '__main__':model = test_rnnrbm() #該函數(shù)主要用來訓(xùn)練RNN-RBM參數(shù)model.generate('sample1.mid') #產(chǎn)生數(shù)據(jù)的v_t初始化都是0model.generate('sample2.mid')pylab.show()?
實(shí)驗(yàn)總結(jié):
關(guān)于bp算法:由于RNN-RBM中對(duì)loss函數(shù)求導(dǎo)用到了BPTT(back propgation through time)算法:BP算法加入了時(shí)間維度。為了加深對(duì)BP算法的理解,重新看了一遍推導(dǎo)過程。bp算法的推導(dǎo)過程是主要是由求導(dǎo)中的鏈?zhǔn)椒▌t得到的。具體算法可參考Martin T.Hagan 的《神經(jīng)網(wǎng)絡(luò)設(shè)計(jì)》第11章(這本書寫得不錯(cuò),翻譯得也還可以)。其思想大概為:損失函數(shù)F對(duì)第m層wij(連接第m層第i個(gè)節(jié)點(diǎn)和第m-1層第j個(gè)節(jié)點(diǎn)之間的權(quán)值)的導(dǎo)數(shù)等于F對(duì)第m層第i個(gè)節(jié)點(diǎn)輸入值的導(dǎo)數(shù),乘上該輸入值對(duì)wij的導(dǎo)數(shù)(很容易知道這個(gè)導(dǎo)數(shù)等于第m-1層第j個(gè)節(jié)點(diǎn)的輸出值)。而F對(duì)第m層第i個(gè)節(jié)點(diǎn)輸入值的導(dǎo)數(shù)值又等于F對(duì)第m+1層輸入值的導(dǎo)數(shù)(這時(shí)需要考慮第m+1中所有的節(jié)點(diǎn))乘以第m+1層輸入值對(duì)第m層第i個(gè)輸入值的導(dǎo)數(shù)(這個(gè)導(dǎo)數(shù)值很容易由激發(fā)函數(shù)的導(dǎo)函數(shù)求得),并且我們通常說的bp算法是誤差方向傳播,這里的第m層誤差指的就是F對(duì)第m層輸入值的導(dǎo)數(shù)。由此可知,可以從最后一層依次往前求解,這就是bp算法的思想,本質(zhì)上是高數(shù)里面的鏈?zhǔn)角髮?dǎo)法則。
? ? ? 另外,實(shí)驗(yàn)中關(guān)于樂理對(duì)應(yīng)的具體細(xì)節(jié)沒有深究。
?
參考資料:
? ? ? ?http://deeplearning.net/tutorial/rnnrbm.html(教程主頁(yè))
? ? ?《神經(jīng)網(wǎng)絡(luò)設(shè)計(jì)》,Martin T.Hagan.
? ? ? ?http://www.cse.unsw.edu.au/~waleed/phd/html/node37.html(RNN圖片來源1)
? ? ? ?Recurrent Neural Networks in Ruby.(RNN圖片來源2)
Learning Recurrent Neural Networks with Hessian-Free Optimization, James Martens,Ilya Sutskever.
Modeling Temporal Dependencies in High-Dimensional Sequences: Application to Polyphonic Music Generation and Transcription, Nicolas Boulanger-Lewandowski,Yoshua Bengio,Pascal Vincent.
? ? ? ?http://www-etud.iro.umontreal.ca/~boulanni/icml2012(rnn-rbm項(xiàng)目主頁(yè))
?
?
?
?
by:tornadomeet? from:http://www.cnblogs.com/tornadomeet總結(jié)
以上是生活随笔為你收集整理的深度学习Deep learning:四十九(RNN-RBM简单理解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 互联网公司GitHub repo 语言使
- 下一篇: PigPen:用Clojure写MapR