数据降维的重要性就不必说了,而用NN(神经网络)来对数据进行大量的降维是从2006开始的,这起源于2006年science上的一篇文章:reducing the dimensionality of data with neural networks,作者就是鼎鼎有名的Hinton,这篇文章也标志着deep learning进入火热的时代。
花了点时间读了下这篇文章,下面是一点笔记:
多层感知机其实在上世纪已经被提出来了,但是为什么它没有得到广泛应用呢?其原因在于对多层非线性网络进行权值优化时很难得到全局的参数。因为一般使用数值优化算法(比如BP算法)时需要随机给网络赋一个值,而当这个权值太大的话,就很容易收敛到”差”的局部收敛点,权值太小的话则在进行误差反向传递时离输入层越近的权值更新越慢,因此优化问题是多层NN没有大规模应用的原因。而本文的作者设计出来的autoencoder深度网络确能够较快的找到比较好的全局最优点,它是用无监督的方法(这里是RBM)先分开对每层网络进行训练,然后将它当做是初始值来微调。这种方法被认为是对PCA的一个非线性泛化方法。
每一层网络的预训练都采用的是RBM方法,其主要思想是是利用能量函数,如下:
给定一张输入图像(暂时是以二值图像为例),我们可以通过调整网络的权值和偏置值使得网络对该输入图像的能量最低。
文章说单层的二值网络不足以模拟大量的数据集,因此一般采用多层网络,即把第一层网络的输出作为第二层网络的输入。并且每增加一个网络层,就会提高网络对输入数据重构的log下界概率值,且上层的网络能够提取出其下层网络更高阶的特征。
图像的预训练和微调,编码和解码的示意图如下:
由上图可以看到,当网络的预训练过程完成后,我们需要把解码部分重新拿回来展开构成整个网络,然后用真实的数据作为样本标签来微调网络的参数。
当网络的输入数据是连续值时,只需将可视层的二进制值改为服从方差为1的高斯分布即可,而第一个隐含层的输出仍然为二进制变量。
文章中包含了多个实验部分,有手写数字体的识别,人脸图像的压缩,新闻主题的提取等。在这些实验的分层训练过程中,其第一个RBM网络的输入层都是其对应的真实数据,且将值归一化到了(0,1).而其它RBM的输入层都是上一个RBM网络输出层的概率值;但是在实际的网络结构中,除了最底层的输入层和最顶层RBM的隐含层是连续值外,其它所有层都是一个二值随机变量。此时最顶层RBM的隐含层是一个高斯分布的随机变量,其均值由该RBM的输入值决定,方差为1。
实验结果1:
这3副图中每幅图的最上面一层是原图,其后面跟着的是用NN重构的图,以及PCA重构的图(可以选取主成分数量不同的PCA和logicPCA或者标准PCA的组合,本人对这logicPCA没有仔细去研究过)。其中左上角那副图是用NN将一个784维的数据直接降到6维!
作者通过实验还发现:如果网络的深度浅到只有1个隐含层时,这时候可以不用对网络进行预训练也同样可以达到很好的效果,但是对网络用RBM进行预训练可以节省后面用BP训练的时间。另外,当网络中参数的个数是相同时,深层网络比浅层网络在测试数据上的重构误差更小,但仅限于两者参数个数相同时。作者在MINIST手写数字识别库中,用的是4个隐含层的网络结构,维数依次为784-500-500-2000-10,其识别误差率减小至1.2%。预训时练得到的网络权值占最终识别率的主要部分,因为预训练中已经隐含了数据的内部结构,而微调时用的标签数据只对参数起到稍许的作用。
下面是用NN实现数据的降维的练习部分,也就是Hition大牛science文章reducing the dimensionality of data with neural networks的code部分,其code下载见:http://www.cs.toronto.edu/~hinton/MatlabForSciencePaper.html。花了点时间阅读并运行了下它的code,其实code主要是2个单独的工程。一个只是用MNIST数据库来进行深度的autoencoder压缩,用的是无监督学习,评价标准是重构误差值MSE。另一个工程是MNIST的手写字体识别,网络的预训练部分用的是无监督的,网络的微调部分用的是有监督的。评价标准准是识别率或者错误率。
MINST降维实验:
本次是训练4个隐含层的autoencoder深度网络结构,输入层维度为784维,4个隐含层维度分别为1000,500,250,30。整个网络权值的获得流程梳理如下:
一些matlab函数:
rem和mod:
通常取模运算也叫取余运算,它们返回结果都是余数.rem和mod唯一的区别在于: 当x和y的正负号一样的时候,两个函数结果是等同的;当x和y的符号不同时,rem函数结果的符号和x的一样,而mod和y一样。这是由于这两个函数的生成机制不同,rem函数采用fix函数,而mod函数采用了floor函数(这两个函数是用来取整的,fix函数向0方向舍入,floor函数向无穷小方向舍入)。rem(x,y)命令返回的是x-n.*y,如果y不等于0,其中的n = fix(x./y),而mod(x,y)返回的是x-n.*y,当y不等于0时,n=floor(x./y)
工程中的m文件:
converter.m:
实现的功能是将样本集从.ubyte格式转换成.ascii格式,然后继续转换成.mat格式。
makebatches.m:
实现的是将原本的2维数据集变成3维的,因为分了多个批次,另外1维表示的是批次。
下面来看下在程序中大致实现RBM权值的优化步骤(假设是一个2层的RBM网络,即只有输入层和输出层,且这两层上的变量是二值变量):
偏置值的优化步骤:
当然了,权值更新和偏置值更新每次迭代都是同时进行的,所以应该是同时收敛的。并且在权值更新公式也可以稍微作下变形,比如加入momentum变量,即本次权值更新的增量会保留一部分上次更新权值的增量值。
函数CG_MNIST形式如下:
function [f, df] = CG_MNIST(VV,Dim,XX);
该函数实现的功能是计算网络代价函数值f,以及f对网络中各个参数值的偏导数df,权值和偏置值是同时处理。其中参数VV为网络中所有参数构成的列向量,参数Dim为每层网络的节点数构成的向量,XX为训练样本集合。f和df分别表示网络的代价函数和偏导函数值。
共轭梯度下降的优化函数形式为:
[X, fX, i] = minimize(X, f, length, P1, P2, P3, ... )
该函数时使用共轭梯度的方法来对参数X进行优化,所以X是网络的参数值,为一个列向量。f是一个函数的名称,它主要是用来计算网络中的代价函数以及代价函数对各个参数X的偏导函数,f的参数值分别为X,以及minimize函数后面的P1,P2,P3,…使用共轭梯度法进行优化的最大线性搜索长度为length。返回值X为找到的最优参数,fX为在此最优参数X下的代价函数,i为线性搜索的长度(即迭代的次数)。
实验结果:
由于在实验过程中,作者将迭代次数设置为200,本人在实验时发现迭代到35次时已经花了6个多小时,所以懒得等那么久了(需长达30多个小时),此时的原始数字和重构数字显示如下:
均方误差结果为:
Train squared error: 4.318
Test squared error: 4.520
MINST识别实验:
MINST手写数字库的识别部分和前面的降维部分其实很相似。首先它也是预训练整个网络,只不过在MINST识别时,预训练的网络部分需要包括输出softmax部分,且这部分预训练时是用的有监督方法的。在微调部分的不同体现在:MINST降维部分是用的无监督方法,即数据的标签为原始的输入数据。而MINST识别部分数据的标签为训练样本的实际标签
在进行MINST手写数字体识别的时候,需要计算加入了softmax部分的网络的代价函数,作者的程序中给出了2个函数。其中第一个函数用于预训练softmax分类器:
function [f, df] = CG_CLASSIFY_INIT(VV,Dim,w3probs,target);
该函数是专门针对softmax分类器那部分预训练用的,因为一开始的rbm预训练部分没有包括输出层softmax网络。输入参数VV表示整个网络的权值向量(也包括了softmax那一部分),Dim为sofmmax对应部分的2层网络节点个数的向量,w3probs为训练softmax所用的样本集,target为对应样本集的标签。f和df分别为softmax网络的代价函数和代价函数的偏导数。
另一个才是真正的计算网络微调的代价函数:
function [f, df] = CG_CLASSIFY(VV,Dim,XX,target);
函数输入值VV代表网络的参数向量,Dim为每层网络的节点数向量,XX为训练样本集,target为训练样本集的标签,f和df分别为整个网络的代价函数以及代价函数的偏导数。
实验结果:
作者采用的1个输入层,3个隐含层和一个softmax分类层的输出层,网络的节点数依次为:784-500-500-2000-10。
其最终识别的错误率为:1.2%.
实验总结:
1. 终于阅读了一个RBM的源码了,以前看那些各种公式的理论,现在有了对应的code,读对应的code起来就是爽!
2. 这里由于用的是整个图片进行训练(不是用的它们的patch部分),所以没有对应的convolution和pooling,因此预训练网络结构时下一个rbm网络的输入就是上一个rbm网络的输出,且当没有加入softmax时的微调阶段用的依旧是无监督的学习(此时的标签依旧为原始的输入数据);而当加入了softmax后的微调部分用的就是训练样本的真实标签了,因为此时需要进行分类。
3. 深度越深,则网络的微调时间越长,需要很多时间收敛,即使是进行了预训练。
4. 暂时还没弄懂要是针对大图片采用covolution训练时,第二层网络的数据来源是什么,有可能和上面的一样,是上层网络的输出(但是此时微调怎么办呢,不用标签数据?)也有可能是大图片经过第一层网络covolution,pooling后的输出值(如果是这样的话,网络的代价函数就不好弄了,因为里面有convolution和pooling操作)。