Home

拼搭小怪

智能体设计师


Blog Github

UFLDL:深度学习课程总结

UFLDL 是斯坦福大学 CS294A课程 的教学 wiki。课程设置很科学,循序渐进,每次课程都是在上次的基础上增添一些东西,还有作业可以让你直观地感受所学内容。虽然没有涉及 RNN (循环神经网络),但作为 CNN(卷积神经网络)的基础课程还是很不错的。 如果你对 监督学习逻辑回归梯度下降 等基础概念并不熟悉,可以先学习 之前的课程
关于课程作业的 Python 代码已经放到了 Github 上,点击 课程代码 就能去 Github 查看,代码中的错误和改进欢迎大家指出。

稀疏自编码器

大家知道现在深度学习在计算机视觉领域全面开花结果,得到了许多之前无法想象的好结果。而就在这之前大家还要花费很大的精力来人工设计特征。这部分学习的 稀疏自编码器 正是向自动学习特征迈出的第一步,也是这门课程的基础。( 下图为作业中的神经网络,左图为输入图像,右图为训练后的输出图像 )

稀疏自编码器 的基本模型是一个三层的神经网络,在学习时让网络输出的目标值接近于输入的图像本身,从而学习图像中的特征。直接学习一个恒等函数的话没有什么意义,所以我们要对隐含层做出一些限制,比如减小神经元的个数,网络就会被迫压缩数据并尝试重建输入图像( 类似 PCA 所做的降维 )。当我们加入惩罚让神经元在大部分情况下都不激活的时候,网络能够学习到十分有趣的边缘特征。隐含层的神经元在观察到输入图像中某个特定角度的边缘特征时才会被激活( 下图为作业的训练结果,这和神经科学发现的人类视觉皮层V1中的神经元的激活方式相似 )。

对于 稀疏自编码器 详细的学习方法,可以参考 上一篇文章

向量化

向量化 是在代码中竟可能地使用向量运算来代替原有 For 循环。由于能够使用向量运算的库通常对向量运算进行过优化,所以可以大大加速代码的执行速度。

举一段 反向传播 算法中的例子,它的作用是对于每一组数据运行反向传播并累计误差。

1
2
3
4
5
for i in range(m):
d3 = (a3[i] - data[i]) * a3[i] * (1.0 - a3[i])
d2 = (np.dot(d3,Theta2)[1:] + beta * sparsity_delta) * a2[i][1:] * (1.0 - a2[i][1:])
delta1 = delta1 + np.dot(d2.reshape(-1,1),a1[[i]])
delta2 = delta2 + np.dot(d3.reshape(-1,1),a2[[i]])

wiki 中有建议将这段代码向量化,不过没有给出具体的伪代码。笔者原以为最后只剩这部分没改的话对效率也不会有十分大的影响,但事实是向量化之后,学习速度得到了明显的提升 Orz。( 这个章节对于后面的课程可以说是必须的,因为最痛苦的事莫过于学习速度很慢,你的代码又有问题需要重新学习 )

1
2
3
4
d3 = (a3 - data) * a3 * (1.0 - a3)
d2 = (np.dot(d3, Theta2)[:,1:] + beta * sparsity_delta) * a2[:,1:] * (1.0 - a2[:,1:])
delta1 = np.dot(d2.T, a1)
delta2 = np.dot(d3.T, a2)

作业将 稀疏自编码器 使用在 MNIST 数据集上,学习到了很有意思的边缘特征。

预处理

课程中使用的预处理为 ZCA Whitening,它的想法是去除输入特征的相关性。首先将特征变换到无相关性的坐标下,通过相关性系数拉伸,再变换到原先的坐标系,使得特征在原先坐标系下不再相关。( 对于二维特征,整个过程如下图 )

事实证明这也是一种视网膜处理图像的粗糙模型。具体而言,当你的眼睛感知图像时,由于一幅图像中相邻的部分在亮度上十分相关,大多数临近的“像素”在眼中被感知为相近的值。因此,如果人眼需要分别传输每个像素值(通过视觉神经)到大脑中,会非常不划算。取而代之的是,视网膜进行一个与 ZCA 中相似的去相关操作 ( 这是由视网膜上的 ON-型 和 OFF-型 光感受器细胞将光信号转变为神经信号完成的 )。由此得到对输入图像的更低冗余的表示,并将它传输到大脑。

Softmax

Softmax 这部分,我们使用它来为 稀疏自编码器 自学习到的特征来分类,它的特点是输出向量是归一化的( 和为一 )。不过在之前 MNIST分类问题 中,我们对每个输出层的神经元使用了逻辑回归( 每个输出都是二元分类 )。这就产生了一个问题,什么时候该使用 Softmax,什么时候使用逻辑回归呢?

Ng 告诉我们问题的关键在于类别之间是否互斥。比如我们的手写字符识别问题,每个数字类别是互斥的,你写的数字不可能既是 1 又是 2。如果你的数据可能既属于分类 A 又 属于分类 B,这时候你就需要使用逻辑回归了。

增加深度

这时课程开始渐入正题,Ng 告诉我们 稀疏自编码器 能够自己学习到局部图像的边缘特征,如果使用中间层的输出作为特征再训练一个稀疏自编码器,这时的隐含层会学习如何去组合边,从而构成轮廓、角等更高阶的特征。再加上稀疏自编码器是无监督学习,所以我们可以反复使用这种方式来构建更深的网络,并在最后对整个网络进行 微调 来高效地完成深层网络的训练。

上图是作业中训练的网络,它的整个训练步骤如下:

  1. 使用输入图像训练稀疏自编码器,获得隐含层的权值
  2. 将隐含层的输出作为特征训练第二层稀疏自编码器
  3. 将第二层稀疏自编码器隐含层的输出作为特征,原数据的结果目标值,训练 Softmax 分类器
  4. 微调 整个网络的权值,完成网络的训练

大图像处理

在先前的网络中,隐含层的每个神经元连接了所有输入层的神经元。当训练图片增大时,所要学习的权值也不断增多,以至于训练速度慢到不可接受。受 视觉皮层的神经元只感受局部接受信息 的启发( 同时也是自然图像有其固有特性,也就是说,图像的一部分的统计特性与其他部分是一样的 ),我们可以让隐含层只连接一部分的输入单元来提取特征。

比如输入数据是 96x96 的图片,我们先随机取这些图片中 8x8 的局部图像,用 稀疏自编码器 学习 100 个特征( 隐含层单元及输入的权值,作业中学习到的特征如下图 )。

然后使用每个隐含层神经元,对原图的每个部分做特征提取( 这个过程相当于对原图像做 **卷积** 的操作,如下图 )。对于每张 96x96 的图像,我们将得到 100 个 89x89 的卷积特征图像,用于后续处理。

不难发现,当我在原图上通过卷积提取特征的时候,只有某些位置的激活是最强烈的,所以我们使用 池化 来减小冗余。池化 就是在卷积输出的每个区域,使用均值或者最大值来代替原来的输出,它带来的一个好处是提取的特征对图像的平移不敏感。


经过上述 卷积池化 的处理,特征数量已经大幅减少。最后我们使用这些特征来训练 Softmax 分类器。

后续

通过 Coursera 课程,我们学习了一些基本的 机器学习 算法,对整个领域有了一个大体的认识。UFLDL 课程在它的基础上更近一步,介绍了深度学习中 CNN 的网络架构和学习方法。有了这些基础就不难理解由 CNN 架构演化而来的各种网络( CNN 架构的演进 )。

对于之后要学习的深度学习知识点,一方面考虑学习一下 RNN( 循环神经网络 ),以及基于这个架构演化的用来处理序列的网络;另一方面考虑学习不同的学习方法,比如 强化学习


拼搭小怪

2019-05-08

Blog Github