最近半个月主要在学习UFLDL上的教程,感觉深度比较合适我这种只看过Andrew Ng公开课的新人,在此对UFLDL上的各种算法做一个归类整理。
自编码算法与稀疏性
了解稀疏自编码算法前必须了解神经网络的前向传播与反向传播算法。该部分在Coursera上的公开课也有涉及,并整理过相关笔记,此处不在赘述。需要注意的是,这两份教程在算法上的细节有一些差异,具体来说,UFLDL教程的神经网络算法的代价函数为:$$J(W,b)
= left[ frac{1}{m} sum_{i=1}^m left( frac{1}{2} left| h_{W,b}(x^{(i)}) - y^{(i)}
ight|^2
ight)
ight] + frac{lambda}{2} sum_{l=1}^{n_l-1} ; sum_{i=1}^{s_l} ; sum_{j=1}^{s_{l+1}} left( W^{(l)}_{ji}
ight)^2 $$
而在计算输出层的误差的时候,UFLDL的算法是:$$delta^{(n_l)}_i
= frac{partial}{partial z^{(n_l)}i} ;;
frac{1}{2} left|y - h{W,b}(x)
ight|^2 = - (y_i - a^{(n_l)}_i) cdot f'(z^{(n_l)}_i)$$
而Coursra上的教程则没有导数项。代价函数的选取可能和神经网络的算法用于解决的问题有一定的关系,但是对于输出层的差别笔者没有也不是很明白,希望有了解的不吝赐教。
稀疏自编码算法简介
稀疏自编码算法是一种无监督的学习算法。它的结构类似于神经网络算法,采取相同的反向传播算法,但是其期望的输出和给定的输入相同,用图表示如下:
当神经元的输出接近1的时候我们认为它被激活,而输出接近0的时候认为它被抑制,若使得神经元大部分的时间都是被抑制的限制则被认为是稀疏性限制。
总的来说,稀疏自编码算法和神经网络算法的差别在于:
- 稀疏自编码算法是无监督的,它试图学习一个(h_{W,b}(x) approx x)的函数
- 稀疏自编码会加入稀疏性限制,使得神经元大部分时间被抑制(意思就是对于某个神经元,对于样本中的大部分数据输出都是抑制的,只有少量输出有反应。比如有1000个样本和某个神经元,对于这1000个样本,1000个样本中只有少数几个会在该神经元产生接近1的输出,大部分样本输入后,神经元的输出都为0)
稀疏自编码算法的数学表达
对于稀疏自编码来说,它的实现是通过引入激活度这一概念实现的,使用 (a^{(2)}_j(x))来表示在给定输入为$ x $情况下,自编码神经网络隐藏神经元 $ j $ 的激活度。
进一步,让
表示隐藏神经元 $ j (的平均活跃度(在训练集上取平均),为了实现)hat ho_j = ho( ho$ 是我们自己定义的稀疏性参数,通常取较小的接近0的值来实现稀疏性目的,比如 ( ho = 0.05))。我们定义一个惩罚引子:
也可以表示为:
可以看到,平均激活度和我们期望的稀疏性参数完全一样时,惩罚引子为零,若平均激活度和稀疏性参数相差太远,惩罚引子也会较大。将惩罚引子加入代价函数,就可以限制平均激活度了,此时,代价函数为:
而代价函数更改使得反向传播算法的残差项也有了改变,此时:
稀疏自编码算法的理解与代码
对于稀疏自编码算法来说,它尝试用隐藏层的神经元来完整地涵盖输入信息量,而输出层则可以看作用隐藏层的神经元来还原信息量,这种思路很类似于PCA降维。
在加入稀疏性的限制后,神经元则可以去发现输入数据中的相关性和隐藏的结构。这是因为,某个神经元对于大部分输入都是抑制的,只在某几个特定样本的输入下被激活,这很可能是这几个样本有某些相似性。比如,我们把手写数字作为输入,那么能使得某个神经元被激活的几个样本很可能有一些共性,比如都在图像的某个部位有一条直线或者一个勾等等,因此该神经元其实就是“图像在某个部位有一条直线/一个勾”这种特征的表达。
最后,代码实现可以参考:tornadomeet的博客,看到别人的实现可能才会意识到自己有很多不足吧,代码有很多冗余、向量化也不够完全,个人的代码在这里。
线性解码
稀疏自编码算法在解码时采用的是类似于神经网络的方法,会对加权后的值取sigmoid函数作为激活函数,若使用(f(z)=z)作为激活函数,则输出范围会扩大;此时,不需要对输入数据进行范围缩放。
相应的,在使用BP算法时,计算最后一层误差的(f'(z))修正为(f'(z) = 1)。