注:本文是我学习李宏毅老师《机器学习》课程 2021/2022 的笔记(课程网站 ),文中图片除了一幅我自己绘制的图和一幅来自 Stanford cs231n 教程的图,其余图片均来自课程 PPT。欢迎交流和多多指教,谢谢!
Lecture 3-Image as input
本节课主要介绍应用在图像领域的 Neural Network: Convolutional Neural Network(CNN,卷积神经网络)。
我们先来看看图像识别问题通常是怎么处理的。一般所有的图像会处理成相同大小。如下图所示,把图像输入模型,输出各个类别的概率,以此来判断属于哪个类别,这是个分类问题。
图像是怎么表示的呢?在计算机中用 R, G, B 三色表示图像。例如,下图中大小为 100 x 100 的图片,在 R, G, B 这三个 channels 上各有一个 100 x 100 的矩阵,其中的数值表示强度 ( intensity )。
一个很直观的想法是,把这个矩阵做 flatten 处理,拉直变成一个长的向量,如上图右侧所示。这样,图片的每个像素点都是一个输入,传入之前介绍过的 Neural Network,也就是 Fully Connected Network ,进行训练和预测就好了。
这样可不可以呢?当然可以。
但是,有必要把每个像素点都当作一个输入吗?
如下图所示, 对于大小为 100 x 100 的彩色图像,所需的输入神经元达到
3
×
1
0
4
3\times10^4
3×104 之多。如果输出神经元有 1000 个,那么参数量达到
3
×
1
0
7
3\times 10^7
3×107 。模型的复杂度高,而且运算量巨大。
我们不禁思考,实际中,每个像素点都有这么重要吗?要知道,人类不会仔细到逐像素点地看图片。一般会关注图片的某些特征、区域,而忽略其他。
如何简化?
思路: 通过观察人类是如何看图和辨认的,可以得到一些启发,进而应用到神经网络架构的改进上,使其更适合图像处理。
简化一: Receptive Field
观察一:人类看图像时,是根据 pattern 识别。pattern 可以理解为是一些特征,比如轮廓、花纹等。如下图所示,我们认出鸟儿,一般是看鸟嘴,爪子,羽毛等。这些 patterns 只需看一部分图片。
由此,可以做出简化,比如一次只看 3 x 3 x 3 大小的范围,如下图所示。这样输入一下子减少到了 27,所需的神经元结构简单。这个小的区域就是 Receptive Field。
思考:这一点类似于注意力( attention ),人类擅长专注于最关心的地方,而忽略其他细节。
常用的设定(如下图所示):
- kernel size: 指 receptive field 的宽和高大小。receptive field 的 depth 不需设定,和图像的 depth 相同。
- stride: 指每次 receptive field 移动多少像素点。 一般 stride < kernel size,因为要让相邻 receptive fields 有重叠 (overlap)。
- padding: 为了充分识别到边缘的 pattern,在边缘外补值(比如 0)。
简化二: Parameter Sharing
观察二:同样的 pattern 可能出现在图像的不同区域。比如,下图中的鸟嘴。这样,对于不同的 Receptive Fields,可以使用相同的神经元来探测同一个 pattern。
由此,可以简化:同一个神经元,不同的 receptive fields 之间共享参数,其实就是参数相同。
如下图所示,同一个神经元,对不同的 receptive fields 都使用相同的参数。不同的 receptive fields,输入不同,输出自然也不同。
每个 receptive field 都有一组不同的神经元。Parameter Sharing 是针对同一个神经元的,即下图中颜色和序号一一对应的神经元。
这里,我在学习中有一个很大的困惑:这个 parameter sharing 是怎么并行训练的?因为我想到每次要移动 receptive field,那么上个 receptive field 训练更新的参数又在下一个 receptive field 接着用吗,类似于 batch?
我看了 Stanford cs231n的教程 ,里面介绍了 “Implementation as Matrix Multiplication” ,对我启发很大。这个方法步骤如下:
1.把图片按照设置的 kernel size, stride, padding 等参数,读取 receptive field 的数值,存成一列。比如一张 101x101 大小的彩色图片,假设 kernel size 为 5x5, stride=4。那么,receptive field 大小为 3x5x5=75,把这个三维的 matrix 变成一维向量,长度也是 75。这个图像有多少个 receptive fields 呢?行或列的大小=(101-5)/4+1=25,所以共 25x25=625 个 receptive fields,把这个也变成一维向量,长度是 625。输入就变成了大小为 75x625 的矩阵。
2.weights 参数也做相应转变。其实就是不用再考虑图片二维或三维的对应位置了,按以前 Fully Connected Layer 那样,比如输出 64 个神经元,weights 参数就是大小为 64x75 的矩阵。
3.输入和 weights 相乘得到输出,就是大小为 64x625 的矩阵。看到这里明白了,第一步把数据按 receptive field 扫描读取一遍存成矩阵,后面就可以把这张图片所有的 receptive fields 当成一个 batch,一起进行训练,这样参数共享,参数量为 75x64 ,远小于用 Fully Connected Layer 的 30000x64。
4.训练结束后,再把输出矩阵转变为相应的维度,即 64x25x25。
也就是说,确定了 kernel size, stride 等参数之后,receptive field 就确定了,比如上面的例子里有 25x25 个。取 receptive field 时有重叠区域,现在 想象 我们把这些 receptive fields 按不重叠的方式排成矩阵 ,宽和高都是 25。如下图所示:
因为这 25x25 个 receptive fields 共享参数,做相同处理,所以取一个说明即可。Convolutional Layer 做的运算可以理解为把一个 receptive field 的所有像素点作为输入,比如例子中 receptive field 的大小为 3x5x5,因此输入神经元个数为 75。输出神经元的数目就是输出 “image” 的 depth,比如例子中输出神经元个数为 64,那么输出的 “image” 大小为 64x25x25。为什么这里用引号 “image”呢?因为图像的 depth 一般是 1(黑白图像)或 3(彩色图像),而输出的 depth 不一定是 1 或者 3,通常会是几十或上百。
这篇文章中还给出了输出“image”大小的计算公式,如下图所示。这个很重要,写代码实现网络结构时,要计算出每一层的输入输出大小:
综上所述,Convolutional Layer 是对 Fully Connected Layer 做了两个简化:(1)Receptive Field: 每次只看一部分区域;(2)Parameter Sharing: 对于同一个输出神经元,不同的 receptive fields 使用相同的参数。如下图所示,经过这两个简化,使用的参数量大大减少,这样模型复杂度降低,model bias 更大。
你可能要问:model bias 大了,模型性能就没那么好了,这样的简化合理吗?
Fully Connected Layer 是全能型,可以用于解决各种各样的问题。但是,它在某个特定领域往往不如专门的网络结构好。比如这里的 Convolutional Layer,它针对图像识别的特点进行了网络的设计,因此解决图像问题时表现优秀。
Filter Version
上面的介绍是从 Neuron Network 的角度来看的。我们还可以从 filter(滤波器) 的角度来看这个问题。用一组 filters 对图像做卷积运算。每个 filter 是多大呢,就是 3x3xchannel 大小。你可能发现了,filter 和 Receptive Field 一样大小。
每个 filter 都有系数,比如下图右上角所示为 Filter2 的系数。把 filter 与图像逐区域做点乘(对应位置相乘)求和运算,即得到对应的输出,也叫 Feature Map,如下图右下角大小为 4x4 的蓝色图所示。注意,这里 filter 的系数并不是已知的,是待求的参数 (unknown parameters)。
1个 filter 对图像做 convolution 会得到一个 Feature Map,如果我们把所有 filters 处理图像后得到的 Feature Map 挨个叠起来,像叠千层饼一样,如下图例子所示的 64 个 filters,输出就会有 64 “层”。换言之,输出的 depth 是 64。
疑问:3x3 的范围是不是太小了?每次都看一个小范围,会不会看不出大的 pattern ?
不小,随着层数的增加,对应到原始图像的范围会逐渐扩大。举例说明,如下图所示,第一层 convolutional layer 的输出中,3x3 的区域对应于原图像中 5x5 的区域。因此,对第一层的输出做 filter 大小为 3x3 的 convolution,对应到原图像上,处理的是 5x5 的区域,看的 pattern 更大。随着层数的增加,即使每次都用 3x3 大小的 filter,也能看到越来越大的 pattern。
前面分别从 Neuron 和 Filter 的角度讲了 Convolutional Layer 的原理,这两个版本 Neuron Version Story 和 Filter Version Story,其实是一样的。
为什么这么说呢?我们来看看两者的比较:
1.Neuron Version:神经元的输入是一个 receptive field,而不是整幅图像。
Filter Version:有一组 filters 逐区域检测图像的 patterns。
从下图的对比中可以发现,filters 就是 receptive field 的输出 neurons。
2.Neuron Version:同一种 neuron,不同 receptive fields 之间共享参数(使用相同的参数),如下图所示。
Filter Version:每个 filter 扫描输入图片,分区域依次做 convolution,可见不同区域用的是相同参数。
简化三:Pooling
观察三:我们都有这样的体验,网上下载图片时,有不同的尺寸,比如 1920x1440, 1280x960, 640x480 等,这些图片只是分辨率不同,都可以辨认出里面的图象。如下图所示,对一张鸟儿的图片做 subsampling,比如只保留偶数行和偶数列,得到小图片,其中的鸟儿图像虽然更模糊一点,但是不影响辨认。
因此,可以对 Convolutional Layer 的输出做 subsampling 操作,降低运算量。这里叫做 Pooling,例如:Max Pooling,取一定大小区域内(比如:2x2)的最大值。
与 Receptive Field 的比较:
1.相似之处:都是在某一区域运算。设置区域大小时只设置宽和高,区域的 depth 与图像的 depth 相同。
2.Receptive Field 的运算要学习神经网络的参数,而 Pooling 不用学习参数,只是一个类似激活函数( activation function,例如 sigmoid 或 ReLU ) 的操作。
但是,Pooling 会对性能有影响,尤其是需要识别细微之处时。如果机器的运算能力满足要求,也可以不做 Pooling。
网络架构
卷积神经网络 (CNN) 的基本架构如下图所示,一般在 Convolution 之后做 Pooling(Pooling 可有可无),这样的操作可以叠几层,然后把输出做 flatten 变成向量,最后输入到 Fully Connected Layer,当作一个分类问题处理。
思考:这样看下来,我感觉 Convolutional Layer 是 Feature Engineering (特征工程),提取特征 (pattern) 送入最后的 Fully Connected Layer。
知名的 CNN 架构有:LeNet, AlexNet, VGG, ResNet 等。
下围棋的应用
围棋界大名鼎鼎的 AlphaGo 也是用 CNN 实现的。这一点我没想到,之前我以为是用的强化学习。
下围棋可以用 Fully Connected Layer 实现。对于棋盘上每一个位置,如果放黑子,值为 1;如果放白子,值为 -1;如果未放子,值为 0。把棋盘表示为 19x19 vector 作为输入,输出为下一步落子的位置,棋盘上的每个位置当作一个分类,这就是一个 19x19 个类别的分类问题。
但是,用 CNN 网络实现效果更好。棋局可以用 48x19x19 的 “image” 表示,depth 为 48,表示棋局位置的 48 种状态(depth=48 来自 AlphaGo 论文,由懂围棋的高手根据围棋规则、招式等设计的)。我们可以把这个 “image” 输入CNN,输出分类。
为什么下围棋可以用 CNN 呢?前面介绍了,CNN 是为图像处理设计的网络架构。下围棋和图像有相似之处吗?
有,围棋招式有一定的 patterns,是在棋盘的小区域。而且这些 patterns 可能出现在棋盘的不同位置,比如下图所示的黑子叫吃,可能出现在棋盘的不同地方。
AlphaGo 用了 Pooling 吗?
我们知道,Pooling 操作是 subsampling。对于图像来说,无非是模糊一点,不影响识别。可是,这里表示的是棋局,想象一下,如果抽取奇数或偶数列,那棋局就不同了。能做 Pooling 吗?
李老师找到了 AlphaGo 的论文中介绍架构的部分,发现:AlphaGo 没有做 Pooling。
正如前面所说,Pooling 不是必须的。由此也提示我们,在应用网络架构前,应该根据应用的场景、任务来判断网络结构是否要调整。
CNN 的不足之处
如果对一张图片的部分区域放大,得到的图片无法识别。比如,用类似下图 a 的图片训练模型,识别不了图 b 这种类型。是不是挺奇怪的?这明明就是同一只狗的图片,图 b 只是把图 a 部分放大到同样尺寸而已。
解决这个问题,可以做 data augmentation,通过截取放大的方式,在训练中加入一些图 b 这种类型的图片。或者用 Spatial Transformer Layer。
听课收获
这节课我明白了如何根据图像的特点来简化 Fully Connected Layer,得到 Convolutional Layer。
觉得本文不错的话,请点赞支持一下吧,谢谢!
关注我 宁萌Julie,互相学习,多多交流呀!
参考
1.李宏毅老师《机器学习 2022》,
课程网站:https://speech.ee.ntu.edu.tw/~hylee/ml/2022-spring.php
视频:https://www.bilibili.com/video/BV1Wv411h7kN
2.Stanford cs231n教程-Convolutional Neural Networks:https://cs231n.github.io/convolutional-networks/#conv
版权归原作者 宁萌Julie 所有, 如有侵权,请联系我们删除。