阅读 706

使用卷积神经网络识别手写数字(理论篇一)

“识别手写数字” 在几天之前对我来说还是觉得很厉害的一件事,或许这需要很高深的机器学习的算法?但是这几天看了一些关于神经网络的文章,才发现识别数字其实是一个很简单的事情(当然这里指的是最基本的识别单个数字),甚至可以算是 计算机视觉(Computer Vison)的 “Hello World”。

而在计算机视觉领域,卷积神经网络(Convolution Neural Networks)的出现引领了一场技术革命,它在图像识别方面可以说是大显身手。本文就基于卷积神经网络,对单个数字进行识别。

概览

本质上来讲,识别手写数字要做的事情是图像识别,不管图里面是数字也好,小猫小狗也好,实质上是一样的。我们的输入是一张图片,输出是一个识别结果。

与人类天生拥有的识别能力不同,计算机只能读取一串串二进制数字。为什么程序能够识别图片?这里并没有什么浪漫色彩,不是因为计算机产生了智慧,而仅仅只是一系列数学公式起了作用。

设想我们是如何分别一张照片是否有人脸的,虽然是一眼就能看出,但想象你才刚出生,为什么你能知道照片里那个东西是个人脸,而不是别的东西?

实际上,我们也是经过一步步训练而具备这种能力的。我们首先会辨别,这里有没有一个头?头的左上角、右上角有没有一只眼睛?中间有没有一只鼻子?最后这些答案大部分都是 “有” 的情况下,我们会得出结论:哦,这是一张脸。

而计算机也是一样的道理,它也可以通过判断一张脸的组成是否都存在来判断是否是一张脸。

所以它先辨别有没有一只眼睛,但它怎么知道这是不是眼睛?那因为眼睛由眼珠、眼白组成,他可以先辨别有没有眼珠。但它怎么知道这是不是眼珠?……

你可能已经明白了,这个问题可以一直细分下去,计算机最后能识别的是一个一个像素点。根据像素点的组成,计算机可以判断是否是一个眼睛,同理往上识别一张人脸。这实际上也就是卷积层划分的本质,我们接下来会谈到。

所以,识别其实也没有什么神奇的地方,可以说是数理统计的结果。不过,设计算法并没有这么简单,一张图由数千数万的像素点组成,如何进行训练也是一个关键的问题。这就引出了卷积神经网络,我们会先对图片进行扫描,然后进行压缩,最后才进行计算:

不要被上面的图吓到了,我们识别手写数字也是一样的思路,但看完本文,你会发现它所做的事情其实并不复杂。

神经网络基础

提到卷积神经网络,就不得不先说一下 神经网络(Neural Networks)。我想即使没有研究过机器学习,大部分人对神经网络这个概念也不陌生,它借鉴了生物学上大脑的神经结构,抽象出了计算机领域的神经网络的模型。

一个简单的神经网络可以表示如下:

神经网络分为三个部分:输入层(Input Layer)、隐藏层(Hidden Layer)和 输出层(Output Layer)。层的个数和每层中节点的个数不是固定的,比如在上图的神经网络中只有一个隐藏层,而在实践中,根据场景不同,隐藏层的数量也不尽相同。

每一层由若干个 感知器(perceptrons)组成,也就是图中的节点。感知器接收一些输入,然后产生一个输出。另外,输入层的感知器没有输入,他们分别作为了隐藏层的输入,在隐藏层中,每个感知器进行计算,产出的输出分别作为了输出层的输入,最后经由输出层计算,产出最终结果。

显然,我们可以把感知器看作一个函数:

output = f(x_1, x_2, x_3)

很幸运,这里的 f 非常简单,是一个线性函数。这里有三个输入,所以我们再定义三个 权重(weight)w1、w2、w3 和一个 偏差(bias)b,上式就可以表示为:

output = w_1 * x_1 + w_2 * x_2 + w_3 * x_3 + b

所以,可以简单理解上面提到的神经网络实际上就是进行如下的计算(这里省略了 Sigmoid 函数,之后再提到):

h1 = w_1 * x_1 + w_2 * x_2 + b_1 \\
h2 = w_3 * x_1 + w_4 * x_2 + b_2 \\
o1 = w_5 * h_1 + w_6 * h_2 + b_3

对于这个神经网络而言,训练集包含的是 x1、x2 对应的 o1 值,而我们需要确定的是 w1 到 w6 和 b1 到 b3 一共 9 个变量的值。因为确定这 9 个值后,我们就能根据任意的 x1、x2 来预测对应的 o1 了。

一开始,可以对这 9 个值进行随机赋值,然后直接开始训练。从输入到输出,这是一个 前向(forward)的过程,不过这样只是生成预测值。而根据预测值,我们可以判断神经网络的预测值和真实值相差多少,然后利用 梯度下降 (Gradient Descent)、反向传播(Backward Propagation)从后往前来改变节点的权重和偏差,这样实现一个 “学习” 的过程。

举一个简单的例子,我们对吉他调音的时候,我们首先弹一个音,调音器说 “音高了!”,于是我们将旋钮顺时针扭一下然后再弹,调音器还是说 “音高了!”,于是我们再将旋钮顺时针扭一下,这时调音器说 “音低了!”,我们再逆时针扭 …… 如此反复,最后得到旋钮的最佳位置。

这里调整的过程就是 梯度下降 的过程,可以参考 之前翻译的一篇文章

神经网络的入门推荐阅读 Machine Learning for Beginners: An Introduction to Neural Networks

卷积神经网络基础

简单讲,卷积神经网络是在神经网络上加入了 卷积层(Convolutional layers),卷积层由一些 滤波器(filter)组成,它对原始图像进行扫描,在扫描窗口内,与原始图像做内积(逐个元素相乘再求和)。这个操作就是所谓的 “卷积” 操作,也是卷积神经网络的名字来源。

卷积层

我们的卷积神经网络的第一层就是卷积层,如上所述,它使用滤波器对图片进行扫描。

举个例子,假设图片是 4 * 4 尺寸,滤波器为 3 * 3,那么滤波器将扫描 4 次,产出一个 2 * 2 的矩阵。

原始图片和滤波器:

扫描过程如下:

想一想这是在干什么?我们说过图像识别实际上做的事情就是判断原始图像中是否存在目标物体的组成部分。这个滤波器实际上就是在做这件事情。

再假设滤波器的像素组成为:

那么当原始图像的窗口内有滤波器的图像时,卷积结果就会很大,反之就越小。实际上使用这个图片可以判断原始图片是否有一个老鼠的组成部分:

你也能想到,因为一只老鼠有很多特征,一个滤波器当然是不够的,所以在卷积层里,会有多个滤波器。每一个滤波器扫描完生成一个图层,那么一共就有滤波器数量个图层。

我们要识别的手写数字图片是 28 * 28 像素的,本文中将使用 8 个滤波器。所以卷积层的输入为 28 * 28 = 784 个,经由卷积层处理后,输出为 26 * 26 * 8 个节点。(3 * 3 的滤波器会使尺寸缩小一圈)

池化层

卷积神经网络的第二层称为 池化层(Pooling Layer),它用来降低卷积层输出的特征向量,同时改善结果(不易出现过拟合)。

常见的池化操作有 平均池化(Mean Pooling)和 最大池化(Max Pooling)。本文将使用最大池化。它实际上就是将上层的输入再通过 2 * 2 的滤波器扫描取最大值:

因为像素点之间的值实际上是非常近的,我们没有必要保留所有相邻的像素点,使用池化层处理后,像素点能显著减少,它的输出节点变为 13 * 13 * 8 个。

Softmax 层

Softmax 层是本文中的最后一层,它将神经网络的输出变成了一个概率分布。

这也是我们在神经网络基础一节提到的实际使用公式计算的位置,Softmax 层输入的节点个数为 13 * 13 * 8 = 1352 个,输出节点个数为 10 个,所以我们会有 1352 * 10 个权重,10 个偏差,对十种可能性进行计算。它们分别表示原始图片是 0 - 9 的概率大小,其中的最大值所在位置就是神经网络预测的数字值:

p_0 = w_{(1,1)} * x_1 + w_{(1,2)} * x_2 + ... + w_{(1,1352)} * x_1352 + b_1 \\
p_1 = w_{(2,1)} * x_1 + w_{(2,2)} * x_2 + ... + w_{(2,1352)} * x_{1352} + b_2 \\
... \\
p_9 = w_{(10,1)} * x_1 + w_{(10,2)} * x_2 + ... + w_{(10,1352)} * x_{1352} + b_{10} \\

以上就是整个前向反馈的过程,经过这些实现后,神经网络就可以对一个图片进行预测,但现在只是瞎猜(因为没有任何学习的过程)。接下来需要使用反向传播对权重和偏差进行调整,我们下篇继续。

参考