CNN
CNN 是专门用于影像处理的 Network。
# 1. Image Classification
我们要做影像分类,也就是给机器一张图片,它要去决定说这张图片里面有什么样的东西。
我们假设我们模型输入的图片大小是固定的,都是 100 × 100 的解析度。我们的目标是分类,所以我们把每一个类别都表示成一个 one-hot 向量,把目标叫做
这个 one-hot 向量的 dimension 的长度决定了你的模型可以辨识多少不同种类的东西。
- 我们模型的输出通过 softmax 后输出
,然后我们希望 与 的 Cross Entropy 越小越好
接下来的问题是怎样把一张影像当做一个模型的输入。
对于一个 Machine 来说,一张图片其实是一个三维的 Tensor:
- 一维代表图片的宽,一维代表图片的高,一维代表图片的 channel 数目
这里的一张彩色的图片的每一个 Pixel 都是由 RGB 三个颜色组成,所以这三个 channel 代表了 R G B 三个颜色,长宽代表了这张图片的解析度,即里面像素的数目。
那接下来就可以把一个三维的 Tensor 拉直(Flatten),然后丢到一个 network 里面去了:
- 直接将一个三维 tensor 拉直成一个 vector,这样就得到一个有 100 × 100 × 3 个数字的巨大的 vector 作为 network 的输入
将上面这个巨大 vector 输入一个 Fully Connected Network,这样 input feature vector 的长度就是 100 × 100 × 3:
现在假设第一层的 neuron 数目有 1000 个,那你能计算一下第一层总共有多少个 weight 吗?每一个 neuron 跟输入向量的没一个数值都有一个 weight,所以这样就有
怎样才能在做影像辨识时,避免使用这么多的参数呢?考虑到影像辨识这个问题本身的特性,其实我们并不一定需要 Fully Connected 这件事。现在我们对影像本身的特性做一些观察。
# 2. Observation 1:可以从 critical pattern 来识别图像
我们怎样识别一张图片里的动物是一只鸟呢?对一个影像辨识的系统而言,它要做的就是侦测这张图片里有没有出现一些特别重要的 pattern:
- 有某个 neuron 看到鸟嘴这个 pattern
- 某个 neuron 看到了眼睛这个 pattern
- 又有某个 neuron 看到了鸟抓这个 pattern
也许看到这些 pattern 综合起来就代表说——我们看到了一只鸟。
或许你觉得通过看 pattern 来决定它是什么,这件事情好像不是很聪明,但仔细想想,人是不是也是用同样的方法来看一张图片中有没有一只鸟呢。举例来说,下面这张图片里有什么动物:
你看到这里有个鸟嘴,有一个眼睛,看起来像乌鸦,但他其实是一只猫。所以其实就算是人,我们在判断一个物件的时候往往也是抓最重要的 pattern,然后看到这些 pattern 以后,你很直地说,你看到了某种物件。对机器来说,也许这也是一个有效的方法。
假设我们现在用 neuron 做的事情就是判断有没有某种 pattern 出现,那也许我们并不需要每一个 Neuron 都去看一张完整的图片,因为一些重要的 pattern,比如鸟嘴、眼睛,并不是需要看到完整的图片才能得到这些资讯。
根据这个观察,我们来做第一个简化。
# 3. Simplification 1:Receptive Field
# 3.1 什么是 Receptive Field
我们设定一个区域,称为Receptive Field(感受野),这样每一个 neuron 都只关心自己的 Receptive Field 里面发生的事情就好了。
举例来说,如下图,先定义这个蓝色的 neuron,它的守备范围就是红色方框框起来的一个区域,它就是 Receptive Field,这里面有 3 × 3 × 3 个数值,这样蓝色的 neuron 就只需要关心者一小块范围就好了,不需要在意整张图片里面有什么东西。
那这个 neuron 怎样考虑这个 Receptive Field 里面发生什么样的事情呢?它要做的事情是:
- 把这 3×3×3 的数值拉直,变成一个长度是 3×3×3 也就是 27 维的向量,再把这 27 维的向量作為这个 Neuron 的输入
- 这个 Neuron 会给 27 维的向量的每一个 Dimension 一个 Weight,所以这个 Neuron 有 3×3×3=27 个 Weight
- 再加上 Bias 得到的输出,这个输出再送给下一层的 Neuron 当作输入
每一个 neuron 只考虑自己的 Receptive Field,那这个 Receptive Field 要怎样决定出来呢?这个就要问你自己了:
- 可以蓝色的 neuron 看左上角的 Receptive Field,另一个黄色看右下角的 Receptive Field,不同的 Receptive Field 也可以是重叠的,甚至两个不同的 neuron 守备看到的范围是一样的。
如果你说你要设计很奇怪的 Receptive Field,去解决很特别的问题,那完全是可以的,这都是你自己决定的。
# 3.2 Typical Setting
虽然 Receptive Field 你可以任意设计,但也有最经典的 Receptive Field 的安排方式。
# 1)看所有的 channel
一般在做影像辨识的时候,你可能不会觉得有些 Pattern 只出现某一个 Channel 里面,所以会看全部的 Channel。
既然会看全部 channel,那我们在描述一个 Receptive Field 的时候,只要讲它的长宽就好了,就不用讲它的深度了,反正深度一定要考虑全部的 channel,而这个长宽合起来叫做 kernel size。
我们刚刚的 kernel size 大小是 3 × 3,有人可能会疑问如果 kernel size 都是 3 × 3,那在做影像辨识时,不一定重要的 Pattern 都只在 3×3 这么小的范围内,也许有些 pattern 很大,这样就没办法侦测出来了呀。等会我们会回答这个问题。
说一下常见的 Receptive Field 设定方式:就是 Kernel Size 3×3,然后一般同一个 Receptive Field,不会只有一个 Neuron 去关照它,往往会有一组 Neuron 去守备它,比如说 64 个或者是 128 个 Neuron 去守备一个 Receptive Field 的范围。
# 2)Stride
到目前为止我们讲的都是一个 Receptive Field,那各个不同 Receptive Field 之间的关系是怎么样呢?你会把你在最左上角的这个 Receptive Field 往右移一点,然后制造一个另外一个 Receptive Field,这个移动的量叫做 Stride。
Stride 是一个你自己决定的 Hyperparameter。但这个 Stride 你往往不会设太大,往往设 1 或 2 就可以了。因为你希望这些 Receptive Field 之间是有重叠的,因为假设有一个 Pattern 就正好出现在两个 Receptive Field 的交界上面,那没有重叠的 Receptive Field 会 miss 掉这个 Pattern。所以我们希望 Receptive Field 彼此之间有高度的重叠。
# 3)padding
移动 Receptive Field 时超出了影像的范围怎么办呢?那就是 padding,即补值:
有多个补值方法:补 0、补整张图片所有 value 的平均值、把边边上的数字补上去。
# 4)Receptive Field 竖着移动
除了这个横着移动,你也会有这个垂直方向上的移动:
# 4. Observation 2:同样的 pattern 可能出现在不同区域
第二个观察就是,同样的 Pattern,它可能会出现在图片的不同区域里面:
按照我们刚才的讨论,你同样的 Pattern,出现在图片的不同的位置,似乎也不是太大的问题,因為出现在左上角的鸟嘴,它一定落在某一个 Receptive Field 裡面,因為 Receptive Field 是移动完之后会覆盖满整个图片的,所以图片裡面没有任何地方不是在某个 Neuron 的守备范围内。那假设在那个 Receptive Field 裡面,有一个 Neuron 它的工作,就是侦测鸟嘴的话,那鸟嘴就会被侦测出来:
但这边的问题是,这些侦测鸟嘴的 Neuron,它们做的事情其实是一样的,只是它们守备的范围是不一样,我们真的需要每一个守备范围,都去放一个侦测鸟嘴的 Neuron 吗?如果不同的守备范围都要有一个侦测鸟嘴的 Neuron,那参数量就太多了。
这就比如,不同专业的学生都需要学习高等数学,那教务处可以开一门大课,然后让不同专业的学生共同来修这门课。
# 5. Simplification 2:权值共享
# 5.1 什么是权值共享
如果放在影像处理上的话,我们能不能够让不同 Receptive Field 的 neuron共享参数?这就是 权值共享。
所谓共享参数就是,这两个 Neuron 它们的 weights 完全是一样的,上图特别用颜色来表示它们的 weights 完全是一样的。比如上下两个 neuron 的第一个 weight 都是 w1,都用红色来表示。
这两个 neuron 守备的 Receptive Field 是不一样的,但他们的参数是一模一样。尽管参数相同,但由于输入不同,输出也自然不同。这就是第二个简化。
# 5.2 Typical Setting
我们让一些 Neuron 可以共享参数,那至于要怎么共享,你完全可以自己决定,而这个是你可以自己决定的事情。但是接下来还是要告诉大家常见的在影像辨识上面的共享的方法是怎么设定的。
我们刚刚说每一个 Receptive Field 都有一组 Neuron 在负责守备:
比如每个 Receptive Field 有 64 个 neuron 来守备,那他们怎样共享参数呢?我们用一样的颜色代表两个 neuron 共享一样的参数:
由上图可以看出,每一个 Receptive Field 都只有一组相同的参数而已,这些参数有一个名字,叫做 Filter。比如两个红色的 neuron 共用一组参数,这组参数就叫 Filter 1,橙色的叫 Filter 2 …
# 6. Convolutional Layer
# 6.1 Benefit of Convolutional Layer
整理一下,我们先有了弹性最大的 Fully Connected Network,但有时候不需要看整张图片,也许只要看图片的一小部分就可以侦测出重要的 Pattern,所以我们有了 Receptive Field 的概念,这时弹性变小了。而接下来的权值共享又更进一步限制了 Network 的弹性。
Receptive Field 加上 Parameter Sharing,就是 Convolutional Layer。而用到了 Convolutional Layer 的 Network,就叫 Convolutional Neural Network,即 CNN。因此,CNN 的 model bias 是比较大的。
可能有人会说 Model Bias 比较大不是一件坏事吗?实际上,Model Bias 大不一定是坏事:
- 当 model bias 小,model 的 flexibility 很高的时候,它比较容易 Overfitting。比如 Fully Connected Layer 可以做各式各样的事情,它可以有各式各样的变化,但是它可能没有办法在任何特定的任务上做好;
- Convolutional Layer 是专门为影像设计的,利用了影像的特性。
# 6.2 Convolutional Layer
刚刚从影像的特性来介绍了 CNN,现在我们用另一种介绍方式来讲这个 CNN,这个版本是比较常见的说明 CNN 的方式。
Convolutional 的 Layer 就是里面有很多的 Filter:
- 这些 Filter 大小都是 3 × 3 × channel 的 size
一个 Convolutional 的 Layer 裡面就是有一排的 Filter,每一个 Filter 都是一个 3 × 3 × Channel 的 Tensor,每一个 Filter 的作用就是要去图片里面抓取 pattern。怎么抓呢:
- 一次的计算方式:Receptive Field 与 Filter 做一次内积运算(对应位置的数值直接相乘,然后累加起来)。
这个 Filter 1 扫完一遍图片后得到:
接下来再用第 2 个 Filter 去做重复的 process:
Filter 2 扫完整张图片后又得到另外一群数值:
如果我们有 64 个 Filter,那我们就能得到 64 群数字了,所有这些数字有一个名字,叫做 Feature Map。所以当我们把一张图片通过一个 Convolutional Layer,里面有一堆 Filter 的时候,我们产生出来了一个 Feature Map。
新得到的这个 Feature Map 又可以看成另一张新的图片,只是他的 channel 有 64 个,而且这不是 RGB 图片的 channel,在这里每一个 Channel 就对应到一个 Filter。即本来一张图片它三个 Channel,通过一个 Convolution,它变成一张有 64 个 Channel 的新图片。
如果把 Convolutional Layer 叠很多层,那第二层的 Convolution 里面也有一堆的 Filter,这里每一个 Filter 大小也设 3 × 3,但它的深度必须设为 64。
⭐️ Filter 的深度就是它要处理的影像的 Channel。
还有一个疑问,如果我们的 Filter 的大小一直设 3 × 3,会不会让我们的 Network 没有办法看比较大范围的 Pattern 呢?其实不会的,Network 叠得越深,同样是 3 × 3 大小的 Filter,它看的范围会越来越大。
刚才我们讲了两个版本的故事了,那这两个版本的故事是一模一样的。今天特别从两个不同的面讲 CNN 这个东西,希望可以帮助你对 CNN 有更深的了解:
# 7. Observation 3:Pooling
在做影像辨识的时候其实还有第三个常用的东西,叫做 Pooling。它来自于一个观察:
我们把一张比较大的图片做 Subsampling,比如把偶数的 Column 都拿掉,奇数的 Row 都拿掉,图片变成为原来的 1/4,但是不会影响里面是什么东西。于是有了 Pooling 这个设计。
Pooling 本身没有参数,所以它不是一个 layer,没有要 learn 的东西,他就是一个 Operator,行为是固定好的。有多个版本的 Pooling,这里讲解 Max Pooling。
刚才说每一个 Filter 都产生一把数字,做 Pooling 的时候,我们就把这些数字几个几个一组,在每一组里面选一个代表。Max Pooling 就是选最大的那一个作为代表:
你不一定要选最大的那一个,这个是你自己可以决定的,比如还有平均池化。也不一定要 2×2 个一组,这个也是你自己决定的,可以改成 3 × 3 一组。
# 8. The whole CNN
Pooling 做的事情就是把图片变小,Convolution 以后我们会得到一张图片,这一张图片里面有很多的 Channel,那做完 Pooling 以后这张图片的 Channel 数量不变,但是我们会把图片变得比较狭长一点。
在实际中,往往就是 Convolution 跟 Pooling 交替使用。你可能做几次 Convolution 就做一次 Pooling,比如两次 Convolution 一次 Pooling,两次 Convolution 一次 Pooling。
不过如果你要侦测的是非常微细的东西,那你随便做 Subsampling 会对 performance 带来一点伤害。现在由于算力的提高,很多 network 的设计也开始把 Pooling 丢掉,成为 Full Convolution 的 Neural Network。
下面这个可能是一个通常的 CNN 架构:
下面的 Flatten 层会把影像里面本来排成矩阵的样子的东西拉直成一个向量,再把这个向量丢进 Fully Connected 的 Layer 里面。最终还可能经过一个 softmax 来最终得到影像分类的结果。这就是一个经典的影像辨识的 Network。它可能有的样子就是长这样:里面有 Convolution,有 Pooling,有 Flatten,最后再通过几个 Fully Connected 的 Layer 或 Softmax,最终得到影像辨识的结果。
# 9. 应用:Alpha Go
# 9.1 Why CNN for Go playing?
// 此处不再详细展开,可以参考 09_CNN.md · unclestrong/DeepLearning21_note (opens new window)
# 9.2 More Applications
CNN 除了下围棋还有影像以外,近年来也用在语音上,也用在文字处理上,这边我们就不再细讲。
# 9.3 To learn more
其实 CNN 它没有办法处理影像放大缩小,或者是旋转的问题。比如今天你给 CNN 看的狗都是这个大小,它可以辨识说这是一只狗,当你把这个图片放大的时候,它可以辨识说它还是一只狗吗?可能是不行的。
对,CNN 就是这么笨,虽然这个形状是一模一样的,但是如果你把它拉长成向量的话,它里面的数值就是不一样的。虽然你人眼一看觉得它形状很像,但对 CNN 来说它是非常不一样。
所以 CNN 并没有你想像的那么强,那就是为什么在做影像辨识的时候往往都要做 Data Augmentation。所谓 Data Augmentation 的意思就是说,你把你的训练资料,每张图片都里面截一小块出来放大,让 CNN 有看过不同大小的 Pattern,然后把图片旋转,让它有看过某一个物件旋转以后长什么样,CNN 才会做到好的结果。
CNN 不能够处理 Scaling 和 Rotation 的问题,还有一个架构叫 Special Transformer Layer 是可以处理这个问题的,这里不再讲述。