深度学习(十二)稀疏自编码

稀疏自编码

原文地址:http://blog.youkuaiyun.com/hjimce/article/details/49106869

作者:hjimce

一、相关理论

以前刚开始学CNN的时候,就是通过阅读theano的深度学习相关教程源码,对于CNN的整个过程才有了深入理解。之前虽然懂CNN的原理,但是对于其源码层的实现,到底要怎么搞,却有点模糊,之后学了theano的cnn教程后,才知道原来是利用了四维矩阵进行操作。

理解了theano的CNN实现之后,对四维矩阵有了深刻的印象,后来阅读caffe的源码的时候,数据结构blob我就把它理解为了四维矩阵。在这里把自己以前阅读theano的时候,对之前源码的标注贴一下,以供大家学习,源码来自于:http://deeplearning.net/tutorial/学习这些源码,同时我们也可以熟悉theano的使用,好处多多。所以建议刚入门深度学习的,一定要好好学theano的深度学习教程,好好解读源码。

本篇博文主要讲解:《稀疏自编码》算法,及其theano实现,属于深度学习的基础知识,高手请绕道。众所周知,机器学习可以大体分为三大类:监督学习、非监督学习和半监督学习。自编码神经网络是一种无监督学习算法,其实如果我们已经对PCA降维、SVD简化,比较熟悉的话,那么你会发现其实稀疏自编跟它们差不多,一样的简单,一样的无聊……

开始前,我们需要知道什么叫无监督学习,说实话,一年前,我连这个都不懂,因为我本身不是学人工智能方向的、也不是计算机专业、信息专业的。以前虽然学过聚类算法,但是那都是自学,没有系统的进行相关理论的学习,故而也不知道其实聚类算法就是无监督学习。说的简单点吧,所谓的无监督学习,就是不需要标签数据,也就是不需要我们对数据做标注,然后才能进行训练,数据直接拿过来,就可以进行训练了。

自编码的网络结构如下:


既然自编码网络是无标签数据,是怎么进行训练的呢?自编码网络很有意思,网络的输入是X,输出也是X,这样就相当于不需要进行数据标注了,属于无监督学习。那么自编码有什么用呢?你觉得让一个网络,输入是input=x,输出output=x,这样有意思吗?

    从上面自编码的网络结构图,可以看到一开始输入特征是x1……x6,有六个特征,然后隐藏层的神经元只有3个,最后又用这3个神经元,要使得网络的输出尽量接近x1……x6。这就相当于我们输入了一个6维的特征向量,我们先把它降维,降到3维,然后我们利用这三维的特征向量,进行重构原始的数据。这个跟PCA降维一模一样,只不过PCA是通过求解特征向量,进行降维,是一种线性的降维方式,而自编码可以利用神经网络进行降维,是一种非线性降维,当然自编码隐藏层可以很多个神经元,然后我们使用正则化约束项,进行稀疏约束。

    这样好玩吗,有意思吗,把x送进网络中,结果啥也不干,这个便是我学习自编码的时候,最大的疑问了,因为我不知道让一个网络的输入是x,最后输出也是x,这样有什么意义?要解答上面的网络有什么用,我们得从深度学习说起,我们知道,在深度学习中,一般网络都有很多层,因为网络层数一多,训练网络采用的梯度下降,在低层网络会出现梯度弥散的现象,导致了深度网络一直不招人待见。直到2006年的3篇论文改变了这种状况,由Hinton提出了一种深层网络的训练方法,改变了人们对深度学习的态度。Hinton所提出的训练思想,整体过程如下;

1、网络各层参数预训练。我们在以前的神经网络中,参数的初始化都是用随机初始化方法,然而这种方法,对于深层网络,在低层中,参数很难被训练,于是Hinton提出了参数预训练,这个主要就是采用RBM、以及我们本篇博文要讲的自编码,对网络的每一层进行参数初始化。也就是我们这边要学的稀疏自编码就是为了对网络的每一层进行参数初始化,仅仅是为了获得初始的参数值而已。

2、在一个时间里,一个层次的无监督训练,接着之前训练的层次。在每一层学习到的表示作为下一层的输入,对每层网络的进行训练初始化。

3、用有监督训练来调整所有层。

OK,我们回到本篇文章的主题,从上面的解释中,我们知道稀疏自编码仅仅只是为了获得参数的初始值而已。而其实我们上面的网络结构图,仅仅只是为了获取深度学习中,各层网络的初始参数值而已,一般我们训练完上后,就会把重构输出层去掉,只留下隐藏层与输入层的参数。而这些参数值,将作为本层网络,与上层网络的一个连接参数初始值。

二、源码实现

下面还是把theano的相关代码实现,贴一下:

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family:Arial;">import os  
  2. import sys  
  3. import timeit  
  4.   
  5. import numpy  
  6.   
  7. import theano  
  8. import theano.tensor as T  
  9.   
  10.   
  11. from logistic_sgd import load_data  
  12. from utils import tile_raster_images  
  13.   
  14. try:  
  15.     import PIL.Image as Image  
  16. except ImportError:  
  17.     import Image  
  18.   
  19. '''''代码编写参考文献:Contractive Auto-Encoder class 
  20. 这篇文献主要是提出一个约束正则项 
  21. 整个总计算过程,参考文献的公式:7'''  
  22. class cA(object):  
  23.   
  24.     def __init__(self, numpy_rng, input=None, n_visible=784, n_hidden=100,  
  25.                  n_batchsize=1, W=None, bhid=None, bvis=None):  
  26.         """ 
  27.         input:输入训练数据数据, input与n_batchsize是对应的,input中有n_batchsize个样本 
  28.         input每一行代表一个样本,共有n_batchsize个样本 
  29.  
  30.         n_visible:可见层神经元的个数 
  31.  
  32.         n_hidden: 隐藏层神经元个数 
  33.  
  34.         n_batchsize:批量训练,每批数据的个数 
  35.  
  36.         W:输入当隐藏层的全连接权值矩阵,因为使用了tied weight 所以从隐藏到输入的权值 
  37.         矩阵为:W.transpose() 
  38.  
  39.         bhid:从输入到隐藏层的偏置单元 
  40.  
  41.         bvis:从隐藏层的偏置单元 
  42.         """  
  43.         self.n_visible = n_visible  
  44.         self.n_hidden = n_hidden  
  45.         self.n_batchsize = n_batchsize  
  46.         # 如果没有输入W,则在类里面进行初始化  
  47.         if not W:  
  48.             '''''W 采用[-a,a]的均匀采样方法进行初始化,因为后面采用s函数,所以 
  49.            a=4*sqrt(6./(n_visible+n_hidden)) ,矩阵类型theano.config.floatX  
  50.            这样才能保证在GPU上运行'''  
  51.             initial_W = numpy.asarray(  
  52.                 numpy_rng.uniform(  
  53.                     low=-4 * numpy.sqrt(6. / (n_hidden + n_visible)),  
  54.                     high=4 * numpy.sqrt(6. / (n_hidden + n_visible)),  
  55.                     size=(n_visible, n_hidden)  
  56.                 ),  
  57.                 dtype=theano.config.floatX  
  58.             )  
  59.             W = theano.shared(value=initial_W, name='W', borrow=True)  
  60.   
  61.         if not bvis:  
  62.             bvis = theano.shared(value=numpy.zeros(n_visible,  
  63.                                                    dtype=theano.config.floatX),  
  64.                                  borrow=True)  
  65.   
  66.         if not bhid:  
  67.             bhid = theano.shared(value=numpy.zeros(n_hidden,  
  68.                                                    dtype=theano.config.floatX),  
  69.                                  name='b',  
  70.                                  borrow=True)  
  71.   
  72.         self.W = W  
  73.         # 输入到隐藏的偏置单元  
  74.         self.b = bhid  
  75.         # 隐藏到输出的偏置单元  
  76.         self.b_prime = bvis  
  77.         # 使用了tied weights, 所以 W_prime 是 W 的转置  
  78.         self.W_prime = self.W.T  
  79.   
  80.         # 如果没有给定input,那么创建一个  
  81.         if input is None:  
  82.             self.x = T.dmatrix(name='input')  
  83.         else:  
  84.             self.x = input  
  85.   
  86.         self.params = [self.W, self.b, self.b_prime]  
  87.     #1、输入层到隐藏层  
  88.     def get_hidden_values(self, input):  
  89.         return T.nnet.sigmoid(T.dot(input, self.W) + self.b)  
  90.     #2、隐藏层到输出层。重建结果 x' = s(W' h  + b') ,因为文献使用了tied weigth,所以  
  91.     #W'等于W的转置,这个可以百度搜索:自编码,tied weight等关键词  
  92.     def get_reconstructed_input(self, hidden):  
  93.         return T.nnet.sigmoid(T.dot(hidden, self.W_prime) + self.b_prime)  
  94.     #计算 J_i = h_i (1 - h_i) * W_i        
  95.     def get_jacobian(self, hidden, W):  
  96.         return T.reshape(hidden * (1 - hidden),(self.n_batchsize, 1self.n_hidden))*T.reshape(W, (1self.n_visible, self.n_hidden))  
  97.   
  98.     #权值更新函数  
  99.     def get_cost_updates(self, contraction_level, learning_rate):  
  100.         y = self.get_hidden_values(self.x)#输入-》隐藏  
  101.         z = self.get_reconstructed_input(y)#隐藏-》输出  
  102.         J = self.get_jacobian(y, self.W)#y*(1-y)*W  
  103.         #文献Contractive Auto-Encoders:公式4损失函数计算公式  
  104.         self.L_rec = - T.sum(self.x * T.log(z) +(1 - self.x) * T.log(1 - z),axis=1)  
  105.   
  106.         # 因为J是由n_batchsize*n_hidden计算而来,有n_batchsize个样本,所以要求取样本平均值  
  107.         self.L_jacob = T.sum(J ** 2) / self.n_batchsize  
  108.           
  109.         #整个惩罚函数  
  110.         cost = T.mean(self.L_rec) + contraction_level * T.mean(self.L_jacob)  
  111.   
  112.         #对参数求导  
  113.         gparams = T.grad(cost, self.params)  
  114.         #梯度下降法更新参数  
  115.         updates = []  
  116.         for param, gparam in zip(self.params, gparams):  
  117.             updates.append((param, param - learning_rate * gparam))  
  118.   
  119.         return (cost, updates)  
  120.   
  121. #测试验证上面的类是否正确  
  122. def test_cA(learning_rate=0.01, training_epochs=20,  
  123.             dataset='mnist.pkl.gz',  
  124.             batch_size=10, output_folder='cA_plots', contraction_level=.1):  
  125.     """ 
  126.     learning_rate:梯度下降法的学习率 
  127.  
  128.     training_epochs: 最大迭代次数 
  129.      
  130.     contraction_level:为正则项的权重 
  131.  
  132.     """  
  133.     #datasets[0]为训练集,datasets[1]为验证集,datasets[2]为测试集  
  134.     datasets = load_data(dataset)  
  135.     train_set_x, train_set_y = datasets[0]  
  136.   
  137.     # 批量下降法,训练的批数  
  138.     n_train_batches = train_set_x.get_value(borrow=True).shape[0] / batch_size  
  139.   
  140.     # allocate symbolic variables for the data  
  141.     index = T.lscalar()    # 每一批训练数据的索引  
  142.     x = T.matrix('x')  # 每一批训练数据  
  143.   
  144.     if not os.path.isdir(output_folder):  
  145.         os.makedirs(output_folder)  
  146.     os.chdir(output_folder)  
  147.   
  148.   
  149.     rng = numpy.random.RandomState(123)  
  150.   
  151.     ca = cA(numpy_rng=rng, input=x,  
  152.             n_visible=28 * 28, n_hidden=500, n_batchsize=batch_size)  
  153.   
  154.     cost, updates = ca.get_cost_updates(contraction_level=contraction_level,  
  155.                                         learning_rate=learning_rate)  
  156.     #每一批,训练更新函数,输入参数index  
  157.     train_ca = theano.function(  
  158.         [index],  
  159.         [T.mean(ca.L_rec), ca.L_jacob],  
  160.         updates=updates,  
  161.         givens={  
  162.             x: train_set_x[index * batch_size: (index + 1) * batch_size]  
  163.         }  
  164.     )  
  165.   
  166.     start_time = timeit.default_timer()  
  167.   
  168.     ############  
  169.     # TRAINING #  
  170.     ############  
  171.   
  172.     # go through training epochs  
  173.     for epoch in xrange(training_epochs):  
  174.         # go through trainng set  
  175.         c = []  
  176.         for batch_index in xrange(n_train_batches):  
  177.             c.append(train_ca(batch_index))  
  178.   
  179.         c_array = numpy.vstack(c)  
  180.         print 'Training epoch %d, reconstruction cost ' % epoch, numpy.mean(  
  181.             c_array[0]), ' jacobian norm ', numpy.mean(numpy.sqrt(c_array[1]))  
  182.   
  183.     end_time = timeit.default_timer()  
  184.   
  185.     training_time = (end_time - start_time)  
  186.   
  187.     print >> sys.stderr, ('The code for file ' + os.path.split(__file__)[1] +  
  188.                           ' ran for %.2fm' % ((training_time) / 60.))  
  189.     image = Image.fromarray(tile_raster_images(  
  190.         X=ca.W.get_value(borrow=True).T,  
  191.         img_shape=(2828), tile_shape=(1010),  
  192.         tile_spacing=(11)))  
  193.   
  194.     image.save('cae_filters.png')  
  195.   
  196.     os.chdir('../')  
  197.   
  198.   
  199. if __name__ == '__main__':  
  200.     test_cA()</span>  

上面的代码,来自:http://deeplearning.net/tutorial/。主要是根据文献:《Contractive Auto-Encoder 》进行编写的代码,代码中,我们需要知道tie-weight、以及文献所提出的损失函数,所以要阅读上面的源码,还是需要把这篇文献看一下。

参考文献:

1、《Contractive Auto-Encoder》

2、http://deeplearning.net/tutorial/ 

**********************作者:hjimce   时间:2015.10.13  联系QQ:1393852684   地址:http://blog.youkuaiyun.com/hjimce   原创文章,版权所有,转载请保留本行信息(不允许删除)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值