目录
计算机视觉作为一门让机器学会如何去“看”的科学学科,具体的说,就是 让机器去识别摄像机拍摄的图片或视频中的物体,检测出物体所在的位置,并对目标物体进行跟踪,从而理解并描述出图片或视频里的场景和故事,以此来模拟人脑视觉系统。因此,计算机视觉也通常被叫做机器视觉,其 目的是建立能够从图像或者视频中“感知”信息的人工系统。
计算机视觉技术经过几十年的发展,已经在
- 交通(车牌识别、道路违章抓拍)
- 安防(人脸闸机、小区监控)
- 金融(刷脸支付、柜台的自动票据识别)
- 医疗(医疗影像诊断)
- 工业生产(产品缺陷自动检测)
等多个领域应用,影响或正在改变人们的日常生活和工业生产方式。未来,随着技术的不断演进,必将涌现出更多的产品应用,为我们的生活创造更大的便利和更广阔的机会。
图1:计算机视觉技术在各领域的应用
飞桨为计算机视觉任务提供了丰富的API,并通过底层优化和加速保证了这些API的性能。同时,飞桨还提供了丰富的模型库,覆盖图像分类、检测、分割、文字识别和视频理解等多个领域。用户可以直接使用这些API组建模型,也可以在飞桨提供的模型库基础上进行二次研发。
本章将重点介绍计算机视觉的经典模型(卷积神经网络)和两个典型任务(图像分类和目标检测)。主要涵盖如下内容:
-
卷积神经网络:卷积神经网络(Convolutional Neural Networks, CNN)是计算机视觉技术最经典的模型结构。本教程主要介绍卷积神经网络的常用模块,包括:卷积、池化、激活函数、批归一化、Dropout等。
-
图像分类:介绍图像分类算法的经典模型结构,包括:LeNet、AlexNet、VGG、GoogLeNet、ResNet,并通过眼疾筛查的案例展示算法的应用。
-
目标检测:介绍目标检测YOLO-V3算法,并通过林业病虫害检测案例展示YOLO-V3算法的应用。
计算机视觉的发展历程
计算机视觉的发展历程要从生物视觉讲起。对于生物视觉的起源,目前学术界尚没有形成定论。有研究者认为最早的生物视觉形成于距今约7亿年前的水母之中,也有研究者认为生物视觉产生于距今约5亿年前寒武纪【1, 2】。寒武纪生物大爆发的原因一直是个未解之谜,不过可以肯定的是 在寒武纪动物具有了视觉能力,捕食者可以更容易地发现猎物,被捕食者也可以更早的发现天敌的位置。视觉能力加剧了猎手和猎物之间的博弈,也催生出更加激烈的生存演化规则。视觉系统的形成有力地推动了食物链的演化,加速了生物进化过程,是生物发展史上重要的里程碑。经过几亿年的演化,目前人类的视觉系统已经具备非常高的复杂度和强大的功能,人脑中神经元数目达到了1000亿个,这些神经元通过网络互相连接,这样庞大的视觉神经网络使得我们可以很轻松的观察周围的世界,如 图2 所示。
图2:人类视觉感知
对人类来说,识别猫和狗是件非常容易的事。但对计算机来说,即使是一个精通编程的高手,也很难轻松写出具有通用性的程序(比如:假设程序认为体型大的是狗,体型小的是猫,但由于拍摄角度不同,可能一张图片上猫占据的像素比狗还多)。那么,如何让计算机也能像人一样看懂周围的世界呢?研究者尝试着从不同的角度去解决这个问题,由此也发展出 一系列的子任务,如 图3 所示。
图3:计算机视觉子任务示意图
-
( a ) Image Classification: 图像分类,用于识别图像中物体的类别(如:bottle、cup、cube)。
-
( b ) Object Localization: 目标检测,用于检测图像中每个物体的类别,并准确标出它们的位置。
-
( c ) Semantic Segmentation: 图像语义分割,用于标出图像中每个像素点所属的类别,属于同一类别的像素点用一个颜色标识。
-
( d ) Instance Segmentation: 实例分割,值得注意的是,(b)中的目标检测任务只需要标注出物体位置,而(d)中的实例分割任务不仅要标注出物体位置,还需要标注出物体的外形轮廓。
在早期的图像分类任务中,通常是先人工提取图像特征,再用机器学习算法对这些特征进行分类,分类的结果强依赖于特征提取方法,往往只有经验丰富的研究者才能完成,如 图4 所示。
图4:早期的图像分类任务
在这种背景下,基于神经网络的特征提取方法应运而生。Yann LeCun是最早将卷积神经网络应用到图像识别领域的,其主要逻辑是使用卷积神经网络提取图像特征,并对图像所属类别进行预测,通过训练数据不断调整网络参数,最终形成一套能自动提取图像特征并对这些特征进行分类的网络,如 图5 所示。
图5:早期的卷积神经网络处理图像任务示意
这一方法在手写数字识别任务上取得了极大的成功,但在接下来的时间里,却没有得到很好的发展。其主要原因是
- 数据集不完善,只能处理简单任务,在大尺寸的数据上容易发生过拟合;另一方面是
- 硬件瓶颈,网络模型复杂时,计算速度会特别慢。
目前,随着互联网技术的不断进步,数据量呈现大规模的增长,越来越丰富的数据集不断涌现。另外,得益于硬件能力的提升,计算机的算力也越来越强大。不断有研究者将新的模型和算法应用到计算机视觉领域。由此催生了越来越丰富的模型结构和更加准确的精度,同时 计算机视觉所处理的问题也越来越丰富,包括分类、检测、分割、场景描述、图像生成和风格变换等,甚至还不仅仅局限于2维图片,包括视频处理技术和3D视觉等。
卷积神经网络
卷积神经网络是目前计算机视觉中使用最普遍的模型结构。本章节主要为读者介绍卷积神经网络的一些基础模块,包括:
- 卷积(Convolution)
- 池化(Pooling)
- ReLU激活函数
- 批归一化(Batch Normalization)
- 丢弃法(Dropout)
回顾一下,在上一章“一个案例带你吃透深度学习”中,我们介绍了手写数字识别任务,应用的是全连接层的特征提取,即将一张图片上的所有像素点展开成一个1维向量输入网络,存在如下两个问题:
1. 输入数据的空间信息被丢失。 空间上相邻的像素点往往具有相似的RGB值,RGB的各个通道之间的数据通常密切相关,但是转化成1维向量时,这些信息被丢失。同时,图像数据的形状信息中,可能隐藏着某种本质的模式,但是转变成1维向量输入全连接神经网络时,这些模式也会被忽略。
2. 模型参数过多,容易发生过拟合。 在手写数字识别案例中,每个像素点都要跟所有输出的神经元相连接。当图片尺寸变大时,输入神经元的个数会按图片尺寸的平方增大,导致模型参数过多,容易发生过拟合。
为了解决上述问题,我们引入卷积神经网络进行特征提取,既能提取到相邻像素点之间的特征模式,又能保证参数的个数不随图片尺寸变化。图6 是一个典型的卷积神经网络结构,多层卷积和池化层组合作用在输入图片上,在网络的最后通常会加入一系列全连接层,ReLU激活函数一般加在卷积或者全连接层的输出上,网络中通常还会加入Dropout来防止过拟合。
图6:卷积神经网络经典结构
说明:
在卷积神经网络中,计算范围是在像素点的空间邻域内进行的,卷积核参数的数目也远小于全连接层。卷积核本身与输入图片大小无关,它代表了对空间邻域内某种特征模式的提取。比如,有些卷积核提取物体边缘特征,有些卷积核提取物体拐角处的特征,图像上不同区域共享同一个卷积核。当输入图片大小不一样时,仍然可以使用同一个卷积核进行操作。
卷积(Convolution)
这一小节将为读者介绍卷积算法的原理和实现方案,并通过具体的案例展示如何使用卷积对图片进行操作,主要涵盖如下内容:
-
卷积计算
-
填充(padding)
-
步幅(stride)
-
感受野(Receptive Field)
-
多输入通道、多输出通道和批量操作
-
飞桨卷积API介绍
-
卷积算子应用举例
卷积计算
卷积是数学分析中的一种积分变换的方法,在 图像处理中采用的是卷积的离散形式。这里需要说明的是,在卷积神经网络中,卷积层的实现方式实际上是 数学中定义的互相关 (cross-correlation)运算,与数学分析中的卷积定义有所不同,这里跟其他框架和卷积神经网络的教程保持一致,都使用互相关运算作为卷积的定义,具体的计算过程如 图7 所示。
图7:卷积计算过程
说明:
卷积核(kernel)也被叫做滤波器(filter),假设卷积核的高和宽分别为 k h k_h kh和 k w k_w kw,则将称为 k h × k w k_h\times k_w kh×kw卷积,比如 3 × 5 3\times5 3×5卷积,就是指卷积核的高为3, 宽为5。
- 如图7(a)所示:左边的图大小是 3 × 3 3\times3 3×3,表示输入数据是一个维度为 3 × 3 3\times3 3×3的二维数组;中间的图大小是 2 × 2 2\times2 2×2,表示一个维度为 2 × 2 2\times2 2×2的二维数组,我们将这个二维数组称为卷积核。先将卷积核的左上角与输入数据的左上角(即:输入数据的(0, 0)位置)对齐,把卷积核的每个元素跟其位置对应的输入数据中的元素相乘,再把所有乘积相加,得到卷积输出的第一个结果
0 × 1 + 1 × 2 + 2 × 4 + 3 × 5 = 25 ( a ) 0\times1 + 1\times2 + 2\times4 + 3\times5 = 25 \ \ \ \ \ \ \ (a) 0×1+1×2+2×4+3×5=25 (a)
- 如图7(b)所示:将卷积核向右滑动,让卷积核左上角与输入数据中的(0,1)位置对齐,同样将卷积核的每个元素跟其位置对应的输入数据中的元素相乘,再把这4个乘积相加,得到卷积输出的第二个结果,
0 × 2 + 1 × 3 + 2 × 5 + 3 × 6 = 31 ( b ) 0\times2 + 1\times3 + 2\times5 + 3\times6 = 31 \ \ \ \ \ \ \ (b) 0×2+1×3+2×5+3×6=31 (b)
- 如图7(c)所示:将卷积核向下滑动,让卷积核左上角与输入数据中的(1, 0)位置对齐,可以计算得到卷积输出的第三个结果,
0 × 4 + 1 × 5 + 2 × 7 + 3 × 8 = 43 ( c ) 0\times4 + 1\times5 + 2\times7 + 3\times8 = 43 \ \ \ \ \ \ \ (c) 0×4+1×5+2×7+3×8=43 (c)
- 如图7(d)所示:将卷积核向右滑动,让卷积核左上角与输入数据中的(1, 1)位置对齐,可以计算得到卷积输出的第四个结果,
0 × 5 + 1 × 6 + 2 × 8 + 3 × 9 = 49 ( d ) 0\times5 + 1\times6 + 2\times8 + 3\times9 = 49 \ \ \ \ \ \ \ (d) 0×5+1×6+2×8+3×9=49 (d)
卷积核的计算过程可以用下面的数学公式表示,其中 a a a 代表输入图片, b b b 代表输出特征图, w w w 是卷积核参数,它们都是二维数组, ∑ u , v \sum{u,v}{\ } ∑u,v 表示对卷积核参数进行遍历并求和。
b [ i , j ] = ∑ u , v a [ i + u , j + v ] ⋅ w [ u , v ] b[i, j] = \sum_{u,v}{a[i+u, j+v]\cdot w[u, v]} b[i,j]=u,v∑a[i+u,j+v]⋅w[u,v]
举例说明,假如上图中卷积核大小是 2 × 2 2\times 2 2×2,则 u u u可以取0和1, v v v也可以取0和1,也就是说:
b [ i , j ] = a [ i + 0 , j + 0 ] ⋅ w [ 0 , 0 ] + a [ i + 0 , j + 1 ] ⋅ w [ 0 , 1 ] + a [ i + 1 , j + 0 ] ⋅ w [ 1 , 0 ] + a [ i + 1 , j + 1 ] ⋅ w [ 1 , 1 ] b[i, j] = a[i+0, j+0]\cdot w[0, 0] + a[i+0, j+1]\cdot w[0, 1] + a[i+1, j+0]\cdot w[1, 0] + a[i+1, j+1]\cdot w[1, 1] b[i,j]=a[i+0,j+0]⋅w[0,0]+a[i+0,j+1]⋅w[0,1]+a[i+1,j+0]⋅w[1,0]+a[i+1,j+1]⋅w[1,1]
读者可以自行验证,当 [ i , j ] [i, j] [i,j]取不同值时,根据此公式计算的结果与上图中的例子是否一致。
- 【思考】 当卷积核大小为 3 × 3 3 \times 3 3×3时,b和a之间的对应关系应该是怎样的?
其它说明:
在卷积神经网络中,一个卷积算子除了上面描述的 卷积过程 之外,还包括 加上偏置项 的操作。例如假设偏置为1,则上面卷积计算的结果为:
0 × 1 + 1 × 2 + 2 × 4 + 3 × 5 + 1 = 26 0\times1 + 1\times2 + 2\times4 + 3\times5 \mathbf{\ + 1} = 26 0×1+1×2+2×4+3×5 +1=26
0 × 2 + 1 × 3 + 2 × 5 + 3 × 6 + 1 = 32 0\times2 + 1\times3 + 2\times5 + 3\times6 \mathbf{\ + 1} = 32 0×2+1×3+2×5+3×6 +1=32
0 × 4 + 1 × 5 + 2 × 7 + 3 × 8 + 1 = 44 0\times4 + 1\times5 + 2\times7 + 3\times8 \mathbf{\ + 1} = 44 0×4+1×5+2×7+3×8 +1=44
0 × 5 + 1 × 6 + 2 × 8 + 3 × 9 + 1 = 50 0\times5 + 1\times6 + 2\times8 + 3\times9 \mathbf{\ + 1} = 50 0×5+1×6+2×8+3×9 +1=50
填充(padding)
在上面的例子中,输入图片尺寸为 3 × 3 3\times3 3×3,输出图片尺寸为 2 × 2 2\times2 2×2,经过一次卷积之后,图片尺寸变小。卷积输出特征图的尺寸计算方法如下:
H o u t = H − k h + 1 H_{out} = H - k_h + 1 Hout=H−kh+1
W o u t = W − k w + 1 W_{out} = W - k_w + 1 Wout=W−kw+1
如果输入尺寸为4,卷积核大小为3时,输出尺寸为 4 − 3 + 1 = 2 4-3+1=2 4−3+1=2。读者可以自行检查当输入图片和卷积核为其他尺寸时,上述计算式是否成立。通过多次计算我们发现,当卷积核尺寸大于1时,输出特征图的尺寸会小于输入图片尺寸。说明经过多次卷积之后尺寸会不断减小。为了避免卷积之后图片尺寸变小,通常会在图片的外围进行填充(padding),如 图8 所示。
图8:图形填充
-
如图8(a)所示:填充的大小为1,填充值为0。填充之后,输入图片尺寸从 4 × 4 4\times4 4×4变成了 6 × 6 6\times6 6×6,使用 3 × 3 3\times3 3×3的卷积核,输出图片尺寸为 4 × 4 4\times4 4×4。
-
如图8(b)所示:填充的大小为2,填充值为0。填充之后,输入图片尺寸从 4 × 4 4\times4 4×4变成了 8 × 8 8\times8 8×8,使用 3 × 3 3\times3 3×3的卷积核,输出图片尺寸为 6 × 6 6\times6 6×6。
如果在图片高度方向,在第一行之前填充 p h 1 p_{h1} ph1行,在最后一行之后填充 p h 2 p_{h2} ph2行;在图片的宽度方向,在第1列之前填充 p w 1 p_{w1} pw1列,在最后1列之后填充 p w 2 p_{w2} pw2列;则填充之后的图片尺寸为 ( H + p h 1 + p h 2 ) × ( W + p w 1 + p w 2 ) (H + p_{h1} + p_{h2})\times(W + p_{w1} + p_{w2}) (H+ph1+ph2)×(W+pw1+pw2)。经过大小为 k h × k w k_h\times k_w kh×kw的卷积核操作之后,输出图片的尺寸为:
H o u t = H + p h 1 + p h 2 − k h + 1 H_{out} = H + p_{h1} + p_{h2} - k_h + 1 Hout=H+ph1+ph2−kh+1
W o u t = W + p w 1 + p w 2 − k w + 1 W_{out} = W + p_{w1} + p_{w2} - k_w + 1 Wout=W+pw1+pw2−kw+1
在卷积计算过程中,通常会在高度或者宽度的两侧采取等量填充,即 p h 1 = p h 2 = p h , p w 1 = p w 2 = p w p_{h1} = p_{h2} = p_h,\ \ p_{w1} = p_{w2} = p_w ph1=ph2=ph, pw1=pw2=pw,上面计算公式也就变为: