原文链接:Reducing the Dimensionality of Data with Neural Networks
主要思想
(下方大量公式,貌似只能在pc上看。移动端无法显示。)
利用多层神经网络构建encoder,通过优化重构后(reconstruction)的输入$x_{recon}$和原输入$x$之间的cross-entropy函数,实现自动encode的目的。
做法
Hinton把它的算法分成了3部分:Pretraining、Unrolling、Fine-tuning
其中Pretraining就是RBM模型,通过CD-1算法先获得参数W、b的初始值。Unrolling其实就是根据encode的输出,获得重构图像的过程,即decode。有了重构后的输入,再加上原始输入,就可以通过Fine-tuning做进一步的参数调整了。不过,我的实验证明,Pretraining对Fine-tuning确实有一定帮助,但是帮助不大
Pretraining
如果你理解CD(Contrastive Divergence)算法,那么这部分其实很好理解。Hinton使用的就是CD-1 .
首先,RBM的能量函数如下:
$$E(\mathbf v, \mathbf h) = - c^T\mathbf v - b^T\mathbf h - \mathbf{h}^T \bf \cdot W \cdot v$$
其中$h$是feature detector特征描述子,是模型自己学习获得的,被称为隐式hidden变量,其实它就是每层网络的输出,$v$是可见变量,即输入。上一层的$h$就是下一层的$v$。我们的目标就是最小化这个能量函数。
注意我们假设$v$和$h$都是随机变量,所以他们都是正的,因此使得$E$最小的方法,就是$v$和$h$要尽量同时为正,这样$E$就会向负值发展。
关于RBM和CD算法,可以参考这个
假设输入为[0, 1]之间的连续随机变量,那么根据RBM的性质,给定$v$,
$$h_j = \sigma(b_j + W_{j \cdot} \cdot v)$$
其中$\sigma$是logistic sigmoid函数。这是mean-fold的做法。如果使用Gibson采样的话,就从“以上面算出的值为均值的{0, 1}随机过程中”去采样$h_j$。我觉得,如果mini-batch很小的话,使用mean-fold就行了。如果mini-batch很大,那么$h_j$为1的出现频次还是等于上面的值。所以没太大区别。
类似,给定$h$,
$$v_{recon} = \sigma(c_i + W_{\cdot i}^T \cdot h)$$
Enegy based 函数都有一个类似的$\Delta w$更新算法,根据这个算法,可以推出CD-1的更新方法如下:
$$\Delta w = \epsilon(<\mathbf h \cdot \mathbf v>_{data} - <\mathbf h \cdot \mathbf v>_{recon})$$
$$\Delta c = \epsilon(<\mathbf v>_{data} - <\mathbf v>_{recon})$$
$$\Delta b = \epsilon(<\mathbf h>_{data} - <\mathbf h>_{recon})$$
其中$\epsilon$表示learning rate,<>表示{0, 1}随机变量为1的频次,或者说期望。data分式中,h是通过v获得的;recon中,v是通过隐式变量h重构的, h是通过重构后的v重新计算的,所以他们是不同的,这个过程就是CD-1。如果h、v的重构计算k次就是CD-k,如下:
$$v^0\rightarrow{p(h|v^0)}\rightarrow h^0\rightarrow{p(v|h^0)}\rightarrow v^1\rightarrow{p(h|v^1)}\rightarrow h^1$$
另外,在这个阶段我还尝试了一下denoising corruption。发现确实有效果。
Unrolling
非常简单,就是根据encode的结果,和一系列的$W^T$做矩阵乘法,最后得到$v_{recon}$的过程。
Fine-tuning
也很简单,就是stochastic gradient decent过程。只是网络层数多了,目标函数是
$$cost = -\sum_i{v^i \cdot log(v_{recon}^i) + (1-v^i) \cdot log(1 - v_{recon}^i)}$$
多亏有了theano,我们计算梯度的方法简化成了T.grad
函数的调用,根本不用去考虑什么BP算法了,很强大!符号计算已经是所有机器学习框架的标配了。
源代码
代码写的有些乱,有兴趣的可以下载下来看看:github
实验结果
denoising corruption
在pretrain阶段,是对每个层进行单独训练的。在第一层,可以通过检查重构后的图片观察pretrain获得的W到底能有什么效果。
corruption能明显加快能量函数的减小:
其中红色曲线是使用了corruption的能量函数变化曲线。可以看到,corruption的加速效果非常明显。
corruption确实有明显的denoising效果
首先,这是原图:
这个是没有corruption的重构图片:
这是使用了corruption的重构图片:
可以看到,corruption使得重构后的图片有了明显的毛玻璃效果。更重要的是,它重构后的数字好像更加“规整”。比如第二行倒数第二个0. 所以corruption确实迫使模型学到了一些更稳定的特征。
和pca对比
相比于pca分解出来的特征,auto encoder获得的特征显然区分度更加好!
可以通过把784维特征降成2维,然后画出来看看这些特征到底是怎么分布的。结果一目了然
可以看到,RandomizedPCA降成2维后,好像只有0、1、2这3个数能较好的区分出来。而4层级联encoder网络(每层节点数分别为1000、500、250、2)得到的结果基本可以把所有数字的大部分都分解出来。不过,4、7、8、9重叠较多,5好像跟8也有较多重叠,这些从测试集合上也可以理解。
观察重构后的图片,也会非常清楚:
这是pca从2维重构回的“原始图片”
这是神经网络重构出的“原始图片”
简直是差了好几个level!
pretrain貌似对最终结果没有太大影响
尽管pretain能够获得一个比较好的初始W,但是即使不用它,只用Fine-tuning,其实也可以慢慢获得一个类似的结果。而且pretrain花费的时间也很长,所以还不如直接抛弃。deeplearning.net的stack encoder就是这样做的,同时也使用了corruption。
以下是使用/不使用 pretrain的validation error变化曲线:
可以看到,使用pretrain后,validation error变化比较稳定,而且开始阶段确实整体偏小。但是随着训练的持续,即使不使用pretrain,模型也能慢慢达到类似效果(只要不发散)。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。