# 问题引入
假设我们希望用机器学习来实现一个图片分类任务,模型的输入是一张图片,模型的输出是其所属的分类。以一个 100x100
像素的图片为例(作为对比,我们常说的 4K 分辨率指 3840x2160
像素)。
图片可以看作是一个 3 维的 tensor,三个维度分别为:长、宽、通道。对于彩色图片来说,有三个通道,对应着 RGB 三种颜色(计算机存储图片的原理)。由于神经网络的输入只能是一个向量(2 维),所以为了让神经网络能读取一个图片,我们需要先将三维 tensor “平坦化”,将三维的 tensor 按通道维度排列成 2 维的向量,在这个例子中,向量的大小为 300x100
。
我们先考虑用一个全连接神经网络来处理这个图片,假设第一层有 1000 个神经元,任意一个输入到任意一个神经元之间都应存在一个 “权重”。此时,第一层将有 个 “权重”,这还是在不考虑 “偏置”,不考虑 “多层” 网络的情况下。
事实上,想要更新如此海量的参数,对算力要求实在太过庞大,根本就 “train” 不起来。
# 简化:基于局部特征来简化网络结构
人类在识别图片时,图片中的大部分的内容其实是无用的,人类其实是通过一些局部特征来识别物体的,例如下面的图片,第一眼看上去非常像一只乌鸦,因为我们首先看到了 “喙”,结合 “黑色” 的特征,我们很容易联想到乌鸦。但是再往下看,当我们看到了 “尾巴” 这个特征后,我们会反应过来,原来这是一个猫。但是无论我们怎么识别这个动物,周围的黄色地板别没有为我们提供任何有效信息,把它们去掉也并不影响我们识别出这个动物。
# 让模型只关注局部细节
受上面的观察启发,我们发现在进行图像处理时,神经网络其实并不需要整个图像来作为输入,只要神经网络能识别出图片中物体的某些特征就足够完成识别任务了。因此,我们可以考虑按一定的规则来将原图片划分成多个 “小图片”,给一个小图片分配一个或多个神经元来学习。
假设我们将图片划分成 3x3
像素(需要根据实际情况调整,能覆盖住特征即可,覆盖不完全也可以,后面会说)的小图片,并且令每 3 个神经元学习一个小图片,那么此时,对于一个神经元来说,所需更新的 “权重” 就从过去的 个降低到 个,所需运算量就会大大减小了,这就是一种简化。
其中,每个神经元可感知的区域,就叫做感受野(receptive field)。
# 常见问题
# 感受野是否可以重叠,为什么?
感受野可以重叠,也必须重叠,因为在划定感受野时我们并不能保证识别物体所需的特征就正好完整的落在感受野内,所以,最好逐像素的划定感受野,以保证特征可以完整的出现在某些神经元的感受野中。每个感受野相隔的距离称为步长(stride)。
# 感受野的设计是否有规范?
感受野可以根据任务需要随意设计,例如感受野可以只看某个通道、或者感受野的形状也可以是长方形等等、或者也是可以设计不同大小的感受野,总之,一切根据任务需要来。
# 感受野越过图像边界怎么办?
可以直接不填充,也可以根据需要对图像的边缘进行填充,同样,具体怎么填充也可以随意设计。
# 经典设计
这里提供一种经典设计:每个感受野分配 64 个神经元,感受野大小 3x3
,步长为 2,边缘需要进行填充。
# 简化:基于相似特征简化训练过程
人类在识别图片的过程中常常会忽略一点,那就是我们要识别的物体可以在图片中的任意位置,人类会自动忽略物体相对在图片中相对位置的区别,但是对于神经网络来说,由于是不同的神经元来感知不同的区域,所以可能存在某一特征换了个位置,另外一个神经元识别不出的情况。
# 让不同感受野的神经元共享参数
神经网络学习的过程其实就是确定一组参数的过程,我们从单个神经元的角度来看,神经元对某特征的识别可以对应到该神经元的一组参数上,所以,如果我们让不同的神经元共享这一组参数,则可以实现让不同的神经元都可以识别同一特征。这里需要强调的的是,这里的不同的神经元必须是不同感受野的神经元,由于不同的感受野的神经元的输入不同,即使共享同一组参数,仍然会有不同的输出;而如果是同一感受野的神经元的话,共享同一组参数则会使不同神经元输出相同的结果,这并不是我们希望看到的。
进一步来说,其实就是将一组参数和一个特征绑定,记得上文中提到的要让多个神经元来感受同一个感受野吗?是的,让 64 个神经元感受一个感受野,其实就是在模型中预留了 64 个 “可更新” 的特征位,该模型最多可以从图片中提取 64 个不同的特征,且任意一个感受野的神经元都可以识别这种特征。感受同一个感受野的不同神经元我们以 filter x
来命名,第一个称为 filter 1
,以此类推。
这样,我们就可以在训练过程中同步更新多个神经元,任意一个神经元学习到某种特征后,其他感受野的对应的 filter
也会自动的学会这种特征,从而大大简化训练的过程,同时提高模型的泛化能力。
# 从 filter 的角度看待训练过程
前面说过,一个 filter
识别一种特征,这个说法可能稍微有些抽象,我们来给出一个具体的例子:输入是一个 6x6
像素的黑白图片(通道数为 1),感受野为 3x3
,每个感受野设置 64 个神经元去学习,步长为 1,在神经网络中我们仍只考虑 “权重”。
# 一个 filter 识别一种特征
首先来说明为什么一个 filter
可以识别一种特征。
假设 Filter 1
就是一个主对角线全为 1,其他元素都为 - 1 的权重矩阵,那么当且仅当感受野中主对角线全为 1,其他元素全 0 时才能,该神经元的输出可以取得最大值 3,即 Filter 1
识别了特征:有一条从左上到右下的线。
# 从小图片到整个图片
因为一个感受野设置了 64 个神经元,所以第一层卷积层处理后得到的是一个 64 通道,大小为 4x4
的特征 tensor,将该输出交给下一层卷积层,下一个卷积层设置的感受野仍为 3x3
,但是这时,由于 3x3
的感受野中的每一个 Feature
都是从原图片中 3x3x1
的小图片中提取的,即每一个 Feature
都包含了 3x3x1
的像素信息,那么第二层卷积层所能 “感受” 的范围其实是原图片中 5x5x1
大小的区域。
随着卷积层的增多,后面的卷积层中的神经元 “感受” 的范围就会越来越大。
# 简化:基于图片的压缩来简化计算量
一般来说,对图片进行降采样并不影响图片的识别,我们可以采用某种方法来将多个像素合成成一个像素,从而大幅减少图片中的总像素点数,这过程称为 Pooling
。以 Max Pooling
为例, Max Pooling
就是用一个区域内最大的值代替该区域的所有值,从而压缩图片大小。
需要注意的是,无论怎样 Pooling
都一定会减少图片的特征。这种方法一般在过去算力紧张时使用,现在的 CNN 中已经在慢慢减少,甚至完全不使用 Pooling
技术了。
# 总结
卷积神经网络其实就是一种专为处理图像而设计的网络结构。全连接层可以处理任何任务,同样的,也意味着他并不擅长任何任务。在全连接的基础上加入 “感受野” 和 “参数共享”,就诞生了卷积卷积神经网络。
# 参考
- https://www.bilibili.com/video/BV1TD4y137mP?p=20