深度学习_卷积神经网络CNN
深度学习 _ 卷积神经网络 CNN
1. 引入
卷积神经网络(CNN)是一种专门用来处理具有网格结构数据的神经网络.它属于前馈神经网络,它被定义为:至少在某一层用卷积代替了矩阵乘法的神经网络.最常见的应用场景是图像识别.
前篇我们自己动手,用 Python 实现了一个 BP 神经网络,本篇我们在 Keras 框架之下实现卷积神经网络(Keras 框架详见《深度学习 _ 工具》篇).Keras 几乎是搭建 CNN 最简单的工具了,然而原理并不简单:除了基本的神经网络中用的误差函数,激活函数等概念以外(具体详见《深度学习 _BP 神经网络》),CNN 还用到了卷积,池化,DropOut 等方法.将在本文中逐一介绍.
2. 原理
1) 图像识别
先来看看图形学中的图像识别是如何实现的.
我们拿到了原图(图上左),一般先将其转换成灰度图(图上中).然后进行边缘检测,图像处理中常使用计算梯度方法(判断某像素与它相邻像素的差值)检测边缘.在 CNN 中我们用卷积来检测:先设计一个卷积核计算相邻像素的差值,然后用 ReLU(f(x)=max(0,x)) 激活函数将那些差值小的置为 0,即识别为非边缘(看到激活函数的厉害了吧,它把低于阈值的都扔掉了,这可是一般线性变换做不到的).于是得到了边缘图(图上右).处理后的图像是个稀疏的矩阵(多数点值都为 0).
¬为了简化计算,我们希望将图片缩小,但在缩放的过程中,细的边缘线就会被弱化,甚至消失(图下左).在 CNN 中用池化解决这一问题,如果把 3*3 个点缩放到 1 点,”最大池化”会将这 9 个点中最大的值,作为新点的值,于是无论强边缘还是弱边缘都被保留了下来(图下右).
边缘检测只是图像识别的第一步,之后还将识别一些更上层的特征,比如拐角,车轮,汽车的轮廓等等,它们都可由卷积实现.越往后的层越抽象,最终一个神经网络模型建起来和图像处理中的"金字塔"有类似的结构,虽然下层的每个点都是局部的,但是上层的点具有全局性.
2) 卷积
下面来看看卷积到底是什么,它与之前学习的全连接神经网络有什么不同.
卷积定义是:通过两个函数 f 和 g 生成第三个函数的一种数学算子.呵呵,很抽象啊,形象地说,处理图像时,卷积就好像拿着一小块滤镜,把图像从左到右,从上到下,一格一格地扫一遍,如果在滤镜中看到想要的,就在下一层做个标记.看看下图就明白了.
图中是一个二维平面上的卷积运算,输入是一个 4x3 的矩阵,卷积核(Kernel)是 2x2 的矩阵,输出是一个 3x2 的矩阵(卷积不都是 2 维的).这就是卷积——一种特殊的线性运算,考虑以下几种情况:
如果上图中的 w,x,y,z 都为 0.25,则该卷积实现了均值运算(图片的模糊处理)
如果上图中 w+x+y+z=1,则该卷积实现了实现了加权平均.
这个运算是不是有点眼熟,如果把 Input 中各点排着一列,把 Kernel 看成权值参数,则它是一个神经网络的连接.输入层有 12 个元素,隐藏层 1 有 6 个元素(先不管其它层)
如图所示,左则是卷积层,右则是全连接的神经网络,全连接时,共有 126=72 个连接(输入输出),72 种权值;而卷积层只有 24 个连接(核大小 * 输出),4个权值 w,x,y,z,分别用四种颜色标出.此处,引出了两个概念:
共享权值(参数共享):共享权值就是多个连接使用同一权值,卷积神经网络中共享的权值就是卷积核的内容,这样不但减小了学习难度.还带来的”平移等变”的性质,比如集体合影中每张脸都可以使用相同的卷积核(一组权值)识别出来,无论它在图中的什么位置,这样学习一张脸后,就能对每张脸应用相同的处理了.此技术多用于同一状态重复出现的情况下.(若图中只有一张脸,脸相关的卷积核共享作用就不大了)
全连接,局部连接与卷积:全连接就是上一层的每个点都与下一层的每个点连接,每个连接都有其自已的权值;局部连接是只有部分点相互连续;卷积是在局部连续的基础上又共享了权值.
卷积核可以是指定的,也可以是用梯度向前推出来的,可以是聚类算出来的(无监督学习),还可以先取一小块训练,然后用这小块训练的结果定义卷积的核.这取决于我们设计的不同算法.
由此可见,卷积层是两层之间的连接方法,与全连接相比,它大大简化了运算的复杂度,还节省了存储空间.之所以能这样简化是因为图像中距离越近的点关系越大(序列处理也同理:离得越近关系越大).
3) 池化
池化是使用某一位置的相邻输出的总体统计特征来代替网络在该位置的输出,和卷积差不多,它也是层到层之间的运算,经过池化处理,层中节点可能不变,也可能变小(常用它降采样,以减少计算量).
最大池化就是将相邻的N个点作为输入,将其中最大的值输出到下一层.除了最大池化,池化算法还有:取平均值,加权平均等等.
池化具有平移不变性:若对图片进行少量平移,经过池化函数后的大多数输出并不会发生改变,比如最大池化,移动一像素后,区域中最大的值可能仍在该区域内.
同理,在一个稀疏的矩阵中(不一定是图像),假设对 n 点做最大池化,那么只要其中有一点非0,则池化结果非 0.如下图所示,只要手写数据 5 符合其中一个判断标准,则将其识别为数字 5.
池化还经常用于处理不同尺寸的图片:比如有 800x600 和 200*150 两张图,想对它们做同一处理,可通过设定池化的输出为 100x75 来实现保留特征的缩放,以至扩展到任意大小的图片.
基本上卷积网络都用使用池化操作.
4) DropOut
再举个例子,现在我们来识别老鼠,一般老鼠都有两只耳朵,两只眼睛,一个鼻子和一个嘴,它们有各自的形状且都是从上到下排列的.如果严格按照这个规则,那么"一只耳"就不会被识别成老鼠.
为提高鲁棒性,使用了 DropOut 方法.它随机地去掉神经网络中的一些点,用剩余的点训练,假设有一些训练集中的老鼠,被去掉的正是耳朵部分,那么"一只耳"最终也可能由于其它特征都对而被识别.
除了提高鲁棒性,DropOut 还有其它一些优点,比如在卷积神经网络中,由于共享参数,我们训练一小部分的子网络(由 DropOut 剪出),参数共享会使得剩余的子网络也能有同样好的参数设定。保证学习效果的同时,也大大减少了计算量.
DropOut 就如同在层与层之间故意加入了一些噪声,虽然避免了过拟合,但它是一个有损的算法,小的网络使用它可能会丢失一些有用的信息.一般在较大型的网络中使用 DropOut.
5) 总结
卷积,池化,DropOut 都是设计者根据数据的性质,采取的对全连接网络的优化和简化,虽然它们都是有损的,但是对计算和存储的优化也非常明显,使我们有机会将神经网络扩展到成百上千层.
3. 代码
1) 说明
代码的主要功能是根据 Mnist 库的图像数据训练手写数字识别.核心代码在后半部分,它使用了卷积层,池化层,Dropout 层,Flatten 层,和全连接层.
2) 代码
(为了让大家复制粘贴就能运行,还是附上了全部代码)
1 | # -*- coding: utf-8 -*- |
4. CNN 的历史
看 CNN 的发展,从 1998 年 LeCun 的经典之作 LeNet, 到将 ImageNet 图像识别率提高了 10 个百分点的 AlexNet, VGG(加入更多卷积层), GoogleNet(使用了 Inception 一种网中网的结构), 再到 RssNet(使用残差网络),ImageNet 的 Top-5 错误率已经降到 3.57%,低于人眼识别的错误率 5.1%,并且仍在不断进步.这些不断提高的成绩以及在更多领域的应用让神经变得越来越热门.
从图中可见,从 AlexNet 的 3 层全连接神经网络,到 ResNet 的 152 层神经网络,全连接层越来越少,卷积层越来越多.除了算法的进步,人的知识也越来越多越来越细化地溶入了神经网络.
5. 参考
- CNN 的发展史
http://www.cnblogs.com/52machinelearning/p/5821591.html