深度学习(八)RBM受限波尔兹曼机学习-未完待续

RBM受限波尔兹曼机学习

原文地址

作者:hjimce



[python] view plain copy

  1. #coding=utf-8  
  2. import timeit  
  3.   
  4. try:  
  5.     import PIL.Image as Image  
  6. except ImportError:  
  7.     import Image  
  8.   
  9. import numpy  
  10.   
  11. import theano  
  12. import theano.tensor as T  
  13. import os  
  14.   
  15. from theano.tensor.shared_randomstreams import RandomStreams  
  16.   
  17. from utils import tile_raster_images  
  18. from logistic_sgd import load_data  
  19.   
  20.   
  21. #RBM网络结构设置,主要是参数初始化  
  22. class RBM(object):  
  23.     def __init__(self,input=None,n_visible=784,n_hidden=500,W=None,hbias=None,vbias=None,numpy_rng=None,theano_rng=None):  
  24.   
  25.         self.n_visible = n_visible  
  26.         self.n_hidden = n_hidden  
  27.   
  28.         if numpy_rng is None:  
  29.             numpy_rng = numpy.random.RandomState(1234)  
  30.         if theano_rng is None:  
  31.             theano_rng = RandomStreams(numpy_rng.randint(2 ** 30))  
  32.         #参数初始化公式 -4*sqrt(6./(n_visible+n_hidden))  
  33.         if W is None:  
  34.             initial_W = numpy.asarray(  
  35.                 numpy_rng.uniform(  
  36.                     low=-4 * numpy.sqrt(6. / (n_hidden + n_visible)),  
  37.                     high=4 * numpy.sqrt(6. / (n_hidden + n_visible)),  
  38.                     size=(n_visible, n_hidden)  
  39.                 ),  
  40.                 dtype=theano.config.floatX  
  41.             )  
  42.             #在GPU上,多线程权重共享  
  43.             W = theano.shared(value=initial_W, name='W', borrow=True)  
  44.         #隐藏层偏置b初始化为0  
  45.         if hbias is None:  
  46.             hbias = theano.shared(value=numpy.zeros(n_hidden,dtype=theano.config.floatX),name='hbias',borrow=True)  
  47.         #可见层偏置项b初始化为0  
  48.         if vbias is None:  
  49.             vbias = theano.shared(value=numpy.zeros(n_visible,dtype=theano.config.floatX),name='vbias',borrow=True)  
  50.   
  51.         #网络输入  
  52.         self.input = input  
  53.         if not input:  
  54.             self.input = T.matrix('input')  
  55.   
  56.         self.W = W  
  57.         self.hbias = hbias  
  58.         self.vbias = vbias  
  59.         self.theano_rng = theano_rng  
  60.         #网络的所有参数,我们把它们放在一个列表中,以便后续访问  
  61.         self.params = [self.W, self.hbias, self.vbias]  
  62.   
  63.     #能量函数的定义,主要是用于计算可视层的能量  
  64.     def free_energy(self, v_sample):  
  65.         ''''' Function to compute the free energy '''  
  66.         wx_b = T.dot(v_sample, self.W) + self.hbias  
  67.         vbias_term = T.dot(v_sample, self.vbias)  
  68.         hidden_term = T.sum(T.log(1 + T.exp(wx_b)), axis=1)  
  69.         return -hidden_term - vbias_term  
  70.     #前向传导 从可视层到隐藏层,计算p(h=1|v)  
  71.     def propup(self, vis):  
  72.         pre_sigmoid_activation = T.dot(vis, self.W) + self.hbias  
  73.         return [pre_sigmoid_activation, T.nnet.sigmoid(pre_sigmoid_activation)]  
  74.     #根据可视层状态 计算隐藏层状态  
  75.     def sample_h_given_v(self, v0_sample):  
  76.         #计算隐藏层每个神经元为状态1的概率,即 p(h=1|v)  
  77.         pre_sigmoid_h1, h1_mean = self.propup(v0_sample)  
  78.         #根据给定的概率,进行采样,就像抛硬币一样。n表示抛硬币的次数 ,每个神经元随机采样一次,就可以得到每个神经元的状态了  
  79.         #p是生成1的概率,binomial函数生成的是一个0、1数  
  80.         h1_sample = self.theano_rng.binomial(size=h1_mean.shape,n=1,p=h1_mean,dtype=theano.config.floatX)  
  81.         return [pre_sigmoid_h1, h1_mean, h1_sample]  
  82.     #后向传导,从隐藏层到可视层,计算p(v=1|h)  
  83.     def propdown(self, hid):  
  84.         pre_sigmoid_activation = T.dot(hid, self.W.T) + self.vbias  
  85.         return [pre_sigmoid_activation, T.nnet.sigmoid(pre_sigmoid_activation)]  
  86.     #根据隐藏层的状态计算可视层状态  
  87.     def sample_v_given_h(self, h0_sample):  
  88.         pre_sigmoid_v1, v1_mean = self.propdown(h0_sample)  
  89.         v1_sample = self.theano_rng.binomial(size=v1_mean.shape,  
  90.                                              n=1, p=v1_mean,  
  91.                                              dtype=theano.config.floatX)  
  92.         return [pre_sigmoid_v1, v1_mean, v1_sample]  
  93.     #计算从隐藏层-》可视层-》隐藏层的一个状态转移过程,相当于一次的Gibbs sampling采样  
  94.     def gibbs_hvh(self, h0_sample):  
  95.         pre_sigmoid_v1, v1_mean, v1_sample = self.sample_v_given_h(h0_sample)  
  96.         pre_sigmoid_h1, h1_mean, h1_sample = self.sample_h_given_v(v1_sample)  
  97.         return [pre_sigmoid_v1, v1_mean, v1_sample,  
  98.                 pre_sigmoid_h1, h1_mean, h1_sample]  
  99.     #计算从可视层-》隐藏层-》可视层的状态转移过程,相当于一次的Gibbs sampling采样  
  100.     def gibbs_vhv(self, v0_sample):  
  101.         pre_sigmoid_h1, h1_mean, h1_sample = self.sample_h_given_v(v0_sample)  
  102.         pre_sigmoid_v1, v1_mean, v1_sample = self.sample_v_given_h(h1_sample)  
  103.         return [pre_sigmoid_h1, h1_mean, h1_sample,  
  104.                 pre_sigmoid_v1, v1_mean, v1_sample]  
  105.   
  106.     # k用于设置Gibbs sampling采样次数,也就是相当于来回跑了多少次(来回一趟算一次)  
  107.     def get_cost_updates(self, lr=0.1, persistent=None, k=1):  
  108.   
  109.         # 当我们输入数据的时候,首先根据输入x,计算隐藏层的概率分布,概率分布的采样结果  
  110.         pre_sigmoid_ph, ph_mean, ph_sample = self.sample_h_given_v(self.input)  
  111.   
  112.         # decide how to initialize persistent chain:  
  113.         # for CD, we use the newly generate hidden sample  
  114.         # for PCD, we initialize from the old state of the chain  
  115.         if persistent is None:  
  116.             chain_start = ph_sample  
  117.         else:  
  118.             chain_start = persistent  
  119.         #让函数来回跑k次  
  120.         (  
  121.             [  
  122.                 pre_sigmoid_nvs,  
  123.                 nv_means,  
  124.                 nv_samples,  
  125.                 pre_sigmoid_nhs,  
  126.                 nh_means,  
  127.                 nh_samples  
  128.             ],  
  129.             updates  
  130.         ) = theano.scan(self.gibbs_hvh,outputs_info=[NoneNoneNoneNoneNone, chain_start],n_steps=k)  
  131.         #拿到最后一次循环的状态  
  132.         chain_end = nv_samples[-1]  
  133.         #构造损失函数  
  134.         cost = T.mean(self.free_energy(self.input)) - T.mean(  
  135.             self.free_energy(chain_end))  
  136.         #计算梯度,然后进行梯度下降更新  
  137.         gparams = T.grad(cost, self.params, consider_constant=[chain_end])  
  138.         for gparam, param in zip(gparams, self.params):  
  139.             updates[param] = param - gparam * T.cast(lr,dtype=theano.config.floatX)  
  140.   
  141.         if persistent:  
  142.             # Note that this works only if persistent is a shared variable  
  143.             updates[persistent] = nh_samples[-1]  
  144.             # pseudo-likelihood is a better proxy for PCD  
  145.             monitoring_cost = self.get_pseudo_likelihood_cost(updates)  
  146.         else:  
  147.             # reconstruction cross-entropy is a better proxy for CD  
  148.             monitoring_cost = self.get_reconstruction_cost(updates,pre_sigmoid_nvs[-1])  
  149.   
  150.         return monitoring_cost, updates  
  151.         # end-snippet-4  
  152.   
  153.     def get_pseudo_likelihood_cost(self, updates):  
  154.         """Stochastic approximation to the pseudo-likelihood"""  
  155.   
  156.         # index of bit i in expression p(x_i | x_{\i})  
  157.         bit_i_idx = theano.shared(value=0, name='bit_i_idx')  
  158.   
  159.         # binarize the input image by rounding to nearest integer  
  160.         xi = T.round(self.input)  
  161.   
  162.         # calculate free energy for the given bit configuration  
  163.         fe_xi = self.free_energy(xi)  
  164.   
  165.         # flip bit x_i of matrix xi and preserve all other bits x_{\i}  
  166.         # Equivalent to xi[:,bit_i_idx] = 1-xi[:, bit_i_idx], but assigns  
  167.         # the result to xi_flip, instead of working in place on xi.  
  168.         xi_flip = T.set_subtensor(xi[:, bit_i_idx], 1 - xi[:, bit_i_idx])  
  169.   
  170.         # calculate free energy with bit flipped  
  171.         fe_xi_flip = self.free_energy(xi_flip)  
  172.   
  173.         # equivalent to e^(-FE(x_i)) / (e^(-FE(x_i)) + e^(-FE(x_{\i})))  
  174.         cost = T.mean(self.n_visible * T.log(T.nnet.sigmoid(fe_xi_flip -  
  175.                                                             fe_xi)))  
  176.   
  177.         # increment bit_i_idx % number as part of updates  
  178.         updates[bit_i_idx] = (bit_i_idx + 1) % self.n_visible  
  179.   
  180.         return cost  
  181.   
  182.     def get_reconstruction_cost(self, updates, pre_sigmoid_nv):  
  183.         """Approximation to the reconstruction error 
  184.  
  185.         Note that this function requires the pre-sigmoid activation as 
  186.         input.  To understand why this is so you need to understand a 
  187.         bit about how Theano works. Whenever you compile a Theano 
  188.         function, the computational graph that you pass as input gets 
  189.         optimized for speed and stability.  This is done by changing 
  190.         several parts of the subgraphs with others.  One such 
  191.         optimization expresses terms of the form log(sigmoid(x)) in 
  192.         terms of softplus.  We need this optimization for the 
  193.         cross-entropy since sigmoid of numbers larger than 30. (or 
  194.         even less then that) turn to 1. and numbers smaller than 
  195.         -30. turn to 0 which in terms will force theano to compute 
  196.         log(0) and therefore we will get either -inf or NaN as 
  197.         cost. If the value is expressed in terms of softplus we do not 
  198.         get this undesirable behaviour. This optimization usually 
  199.         works fine, but here we have a special case. The sigmoid is 
  200.         applied inside the scan op, while the log is 
  201.         outside. Therefore Theano will only see log(scan(..)) instead 
  202.         of log(sigmoid(..)) and will not apply the wanted 
  203.         optimization. We can not go and replace the sigmoid in scan 
  204.         with something else also, because this only needs to be done 
  205.         on the last step. Therefore the easiest and more efficient way 
  206.         is to get also the pre-sigmoid activation as an output of 
  207.         scan, and apply both the log and sigmoid outside scan such 
  208.         that Theano can catch and optimize the expression. 
  209.  
  210.         """  
  211.   
  212.         cross_entropy = T.mean(  
  213.             T.sum(  
  214.                 self.input * T.log(T.nnet.sigmoid(pre_sigmoid_nv)) +  
  215.                 (1 - self.input) * T.log(1 - T.nnet.sigmoid(pre_sigmoid_nv)),  
  216.                 axis=1  
  217.             )  
  218.         )  
  219.   
  220.         return cross_entropy  
  221.   
  222. #  
  223. def test_rbm(learning_rate=0.1, training_epochs=15,  
  224.              dataset='mnist.pkl.gz', batch_size=20,  
  225.              n_chains=20, n_samples=10, output_folder='rbm_plots',  
  226.              n_hidden=500):  
  227.   
  228.     datasets = load_data(dataset)  
  229.   
  230.     train_set_x, train_set_y = datasets[0]  
  231.     test_set_x, test_set_y = datasets[2]  
  232.   
  233.     #计算训练的批数  
  234.     n_train_batches = train_set_x.get_value(borrow=True).shape[0] / batch_size  
  235.   
  236.   
  237.     index = T.lscalar()    # index to a [mini]batch  
  238.     x = T.matrix('x')  # the data is presented as rasterized images  
  239.   
  240.     rng = numpy.random.RandomState(123)  
  241.     theano_rng = RandomStreams(rng.randint(2 ** 30))  
  242.   
  243.   
  244.     persistent_chain = theano.shared(numpy.zeros((batch_size, n_hidden),dtype=theano.config.floatX),borrow=True)  
  245.   
  246.     #网络构建 ,可视层神经元个数为28*28,隐藏层神经元为500  
  247.     rbm = RBM(input=x, n_visible=28 * 28,n_hidden=n_hidden, numpy_rng=rng, theano_rng=theano_rng)  
  248.   
  249.     # get the cost and the gradient corresponding to one step of CD-15  
  250.     cost, updates = rbm.get_cost_updates(lr=learning_rate,persistent=persistent_chain, k=15)  
  251.   
  252.     #################################  
  253.     #     Training the RBM          #  
  254.     #################################  
  255.     if not os.path.isdir(output_folder):  
  256.         os.makedirs(output_folder)  
  257.     os.chdir(output_folder)  
  258.   
  259.     # start-snippet-5  
  260.     # it is ok for a theano function to have no output  
  261.     # the purpose of train_rbm is solely to update the RBM parameters  
  262.     train_rbm = theano.function([index],cost,updates=updates,givens={x: train_set_x[index * batch_size: (index + 1) * batch_size]},name='train_rbm')  
  263.   
  264.     plotting_time = 0.  
  265.     start_time = timeit.default_timer()  
  266.   
  267.     # go through training epochs  
  268.     for epoch in xrange(training_epochs):  
  269.   
  270.         # go through the training set  
  271.         mean_cost = []  
  272.         for batch_index in xrange(n_train_batches):  
  273.             mean_cost += [train_rbm(batch_index)]  
  274.   
  275.         print 'Training epoch %d, cost is ' % epoch, numpy.mean(mean_cost)  
  276.   
  277.         # Plot filters after each training epoch  
  278.         plotting_start = timeit.default_timer()  
  279.         # Construct image from the weight matrix  
  280.         image = Image.fromarray(  
  281.             tile_raster_images(  
  282.                 X=rbm.W.get_value(borrow=True).T,  
  283.                 img_shape=(2828),  
  284.                 tile_shape=(1010),  
  285.                 tile_spacing=(11)  
  286.             )  
  287.         )  
  288.         image.save('filters_at_epoch_%i.png' % epoch)  
  289.         plotting_stop = timeit.default_timer()  
  290.         plotting_time += (plotting_stop - plotting_start)  
  291.   
  292.     end_time = timeit.default_timer()  
  293.   
  294.     pretraining_time = (end_time - start_time) - plotting_time  
  295.   
  296.     print ('Training took %f minutes' % (pretraining_time / 60.))  
  297.     # end-snippet-5 start-snippet-6  
  298.     #################################  
  299.     #     Sampling from the RBM     #  
  300.     #################################  
  301.     # find out the number of test samples  
  302.     number_of_test_samples = test_set_x.get_value(borrow=True).shape[0]  
  303.   
  304.     # pick random test examples, with which to initialize the persistent chain  
  305.     test_idx = rng.randint(number_of_test_samples - n_chains)  
  306.     persistent_vis_chain = theano.shared(  
  307.         numpy.asarray(  
  308.             test_set_x.get_value(borrow=True)[test_idx:test_idx + n_chains],  
  309.             dtype=theano.config.floatX  
  310.         )  
  311.     )  
  312.     # end-snippet-6 start-snippet-7  
  313.     plot_every = 1000  
  314.     # define one step of Gibbs sampling (mf = mean-field) define a  
  315.     # function that does `plot_every` steps before returning the  
  316.     # sample for plotting  
  317.     (  
  318.         [  
  319.             presig_hids,  
  320.             hid_mfs,  
  321.             hid_samples,  
  322.             presig_vis,  
  323.             vis_mfs,  
  324.             vis_samples  
  325.         ],  
  326.         updates  
  327.     ) = theano.scan(  
  328.         rbm.gibbs_vhv,  
  329.         outputs_info=[NoneNoneNoneNoneNone, persistent_vis_chain],  
  330.         n_steps=plot_every  
  331.     )  
  332.   
  333.     # add to updates the shared variable that takes care of our persistent  
  334.     # chain :.  
  335.     updates.update({persistent_vis_chain: vis_samples[-1]})  
  336.     # construct the function that implements our persistent chain.  
  337.     # we generate the "mean field" activations for plotting and the actual  
  338.     # samples for reinitializing the state of our persistent chain  
  339.     sample_fn = theano.function(  
  340.         [],  
  341.         [  
  342.             vis_mfs[-1],  
  343.             vis_samples[-1]  
  344.         ],  
  345.         updates=updates,  
  346.         name='sample_fn'  
  347.     )  
  348.   
  349.     # create a space to store the image for plotting ( we need to leave  
  350.     # room for the tile_spacing as well)  
  351.     image_data = numpy.zeros(  
  352.         (29 * n_samples + 129 * n_chains - 1),  
  353.         dtype='uint8'  
  354.     )  
  355.     for idx in xrange(n_samples):  
  356.         # generate `plot_every` intermediate samples that we discard,  
  357.         # because successive samples in the chain are too correlated  
  358.         vis_mf, vis_sample = sample_fn()  
  359.         print ' ... plotting sample ', idx  
  360.         image_data[29 * idx:29 * idx + 28, :] = tile_raster_images(  
  361.             X=vis_mf,  
  362.             img_shape=(2828),  
  363.             tile_shape=(1, n_chains),  
  364.             tile_spacing=(11)  
  365.         )  
  366.   
  367.     # construct image  
  368.     image = Image.fromarray(image_data)  
  369.     image.save('samples.png')  
  370.     # end-snippet-7  
  371.     os.chdir('../')  
  372.   
  373. if __name__ == '__main__':  
  374.     test_rbm()  

from: http://blog.csdn.net/hjimce/article/details/48949197
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值