大多数人接触 “语义” 都是在和文字相关的领域,或语音识别,期望机器能够识别你发出去的消息或简短的语音,然后给予你适当的反馈和回复。嗯,看到这里你应该已经猜到了,图像领域也是存在 “语义” 的。

今天是 AI 大热年,很多人都关注与机器人的语音交互,可是有没有想过,将来的机器人如果不能通过图像来识别主人,家里的物品、宠物,那该多没意思。说近一些,假如扫地机器人能够机智地绕开你丢在地上的臭袜子而扫走旁边的纸屑,一定能为你的生活解决不少麻烦。

没错,图像语义分割是 AI 领域中一个重要的分支,是机器视觉技术中关于图像理解的重要一环,是不是听上去即重要又牛 X 闪闪的。

近年的自动驾驶技术中,也需要用到这种技术。车载摄像头探查到图像,后台计算机可以自动将图像分割归类,以避让行人和车辆等障碍。

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割


图像分类 语义分割 实例分割_池化_02

图像语义分割

图像语义分割的意思就是机器自动分割并识别出图像中的内容,比如给出一个人骑摩托车的照片,机器判断后应当能够生成右侧图,红色标注为人,绿色是车(黑色表示 back ground)。

图像分类 语义分割 实例分割_卷积_03

所以图像分割对图像理解的意义,就好比读古书首先要断句一样

在 Deeplearning 技术快速发展之前,就已经有了很多做图像分割的技术,其中比较著名的是一种叫做 “Normalized cut” 的图划分方法,简称 “N-cut”。

N-cut 的计算有一些连接权重的公式,这里就不提了,它的思想主要是通过像素和像素之间的关系权重来综合考虑,根据给出的阈值,将图像一分为二

下图是将像素间的关系信息简单描述成为距离,根据距离差距来划分图像的示例:

图像分类 语义分割 实例分割_卷积_04

在实际运用中,每运行一次 N-cut,只能切割一次图片,为了分割出图像上的多个物体,需要多次运行,下图示例了对原图 a 进行 7 次 N-cut 后,每次分割出的结果。

图像分类 语义分割 实例分割_池化_05

但是可以很明显的看到这种简单粗暴的分割方式并不准确,趴在地上的运动员肢体在 b 图中分割出来,而他的手臂则在 h 图中被分割,显然是错误的。

N-cut 技术的缺陷很明显,于是有了一种更新的优化方式,这种优化方式为了避免机器不能很好的分割类似上面例子中 “衣服和肢体颜色反查太大导致分割错误” 的情况,增加了人机交互,在分割过程中,需要人工干预参与完成。

这种需要人机交互的技术叫 Grab Cut

[敲黑板]~~ 注意,PS 里就使用了这种技术。

这种技术其实是这样的,给定一张图片,然后人工在想要抠图(也就是我们说的分割)的区域画一个红框,然后机器会对略小于这个框的内容进行 “主体计算”,嗯,这个 “主体计算” 是我起的名字,为了你们更好的理解背后复杂的设计和公式,因为机器会默认红框中部是用户期望得到的结果,所以将中部作为主体参考,然后剔除和主体差异较大的部分,留下结果。

图像分类 语义分割 实例分割_卷积_06

此技术中,抠出来的部分叫 “前景”,剔除的部分叫 “背景”。

有时候还挺好用的,但是稍微复杂一点的时候问题就来了:比如要抠下面这个戴头盔的大兵,头盔颜色和背后岩石颜色很相近,结果机器就会把头盔部分剔除,同样脖子附近的山岩也被当做了前景而保留了进来。

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割_07

此时又需要进行人工干预了,需要手动在图像上进行标注,画白色线表示是希望保留的前景,红色表示背景,指导辅助机器进行判断,再次运算后,得到了较好的期望结果。

虽然看上去 Grab Cut 给出的结果还不错,但缺点也很明显,首先,它同 N-cut 一样也只能做二类语义分割,说人话就是一次只能分割一类,非黑即白,多个目标图像就要多次运算。其次,它需要人工干预,这个弱点在将来批量化处理和智能时代简直就是死穴

OK,人类的智慧是无止境的,DeepLearning(深度学习)终于开始大行其道了。

深度学习

深度学习是机器学习的一个分支,主要指深度神经网络算法,深度神经网络比普通神经网络层次更多,能够更好地捕捉数据中的深层次关系,得到的模型较为准确,主要用来进行特征学习。

先别急着晕,我们先来看看神经网络是怎么工作的。

神经网络是模仿人的神经元而建立的人工神经元系统,多输入单输出,同时输出又作为下一个神经元的输入……(请自行脑补那张牙舞爪妖孽的神经元细胞~ 什么?没见过?文科生,拖出去~~)

下图表示的是一个单个神经元:

图像分类 语义分割 实例分割_卷积_08

把这些单个神经元组织在一起,便形成了神经网络。下图便是一个三层神经网络结构:

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割_09

上图中最左边的原始输入信息称之为输入层,最右边的神经元称之为输出层(上图中输出层只有一个神经元),中间的叫隐藏层

深度神经网络系统中的层数比较多,达到 8-10 层(普通神经网络的层数通常 3-4 层)。

在此前使用的图像识别算法中,主流的技术是卷积神经网络算法(Convolutional Neural Networks),简称 CNN卷积神经网络就是一种深度神经网络

但是在 2015 年的 CVPR 上发表了一篇很牛 X 的论文(路人甲:请问 CVPR 是神马?答:CVPR 可以简单理解为这个领域的最重量级的会议:国际计算机视觉与模式识别会议),提出了 FCN 即 全卷积神经网络(Fully Convolutional Networks)。

为什么说这个 FCN 论文很牛叉呢?看起来只是多了一个字而已呀,有什么不得了的呢?

嗯,不得不说,真是 “差之毫厘,谬以千里” 啊。

我还是先来帮大家复习一下卷积。

我查了很多书,卷积有各种各样的公式,还有各种各样的推导算法,但是为了降低本文的难读指数,所以我直接跳到卷积的物理意义,不要太 care 那些公式,其实卷积的物理意义,就是 “加权叠加”。

在对图像处理进行卷积时,根据卷积核的大小,输入和输出之间也会有规模上的差异。

来看一张动图(仅做示例)

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割_10

上图左边 5*5 的方块视为图像输入,黄色移动的 3*3 以及里面的数字(*1/*0)是卷积核,该卷积核按照步长为 1 的顺序依次从原始输入的左上角一直移动计算叠加到右下角,卷积核一共移动 9 次。

九次的位置对应到右侧的 3*3 的相应格内,格中的数字便是卷积值,(此处是卷积核所覆盖的面积内元素相乘再累加的结果)。

9 次移动计算完毕后,右侧 3*3 的新矩阵为此次卷积层的计算结果。

如果这么说还是不太好理解,没关系,我有更直观的办法 ^_^。

在实际计算过程中,输入是一张原始图片和滤波器 filter(一组固定的权重,也就是上面我们说的卷积核对应的实际意义)做内积后得到新的二维数据。

不同的滤波器 filter 会得到不同的输出数据,比如轮廓、颜色深浅,如果想提取图像的不同特征,需要用不同的滤波器 filter 提取想要的关于图像的特定信息。

图像分类 语义分割 实例分割_池化_11

上图为一个卷积层中的卷积处理过程,注意上下两次卷积核内容是不同的,所以得到两种处理结果。

等号右边的新的二维信息在 CNN 网络中,会作为下一个卷积层的输入,即在下一个卷积层计算时,右边的图像会作为输入的原始图像。

在 CNN 网络中,一共会进行 5 次卷积层计算。

路人甲:那最后会得到一个什么鬼?

沈 MM:咳咳,在连续的 5 个卷积层计算后,紧跟这的是 3 个全连接层。

路人甲:什么是全连接层?

沈 MM:全连接层,并不是一个二维图像,而是—— 一个一维向量

路人甲已哭晕在厕所。

这三个一维向量的前两个向量长度是 4096,最后一个向量长度是 1000.

为什么是 1000?

因为在 CNN 网络中,有 1000 个分类,最后的这个向量中的 1000 个元素表达的信息是:这张原始输入图片中的东西可能是这 1000 个分类中的物体的概率。

是的,一张图,算了半天,最后给出的是,这张图是个什么玩意的答案。

图像分类 语义分割 实例分割_卷积_12

右侧绿色箭头指向的表示最后一个全连接层的向量中,表示各种物体的概率,上图被识别为一辆车。

好了,上面说的是卷积神经网络 CNN 的处理过程(相信我我已经很简化了)。

那么全卷积神经网络呢?

大家应该注意到,CNN 的输入是图像,输出是一个结果,或者说是一个值,一个概率值。

FCN 提出所追求的是,输入是一张图片是,输出也是一张图片,学习像素到像素的映射

图像分类 语义分割 实例分割_池化_13

上图上半部分是 CNN 网络,下半部分是 CN 网络

那么 “全卷积” 又体现在哪里呢?

CNN 网络中的后三层,都是一维的向量,计算方式不再采用卷积,所以丢失了二维信息,而 FCN 网络中,将这三层全部转化为 1*1 的卷积核所对应等同向量长度的多通道卷积层,使后三层也全部采用卷积计算,整个模型中,全部都是卷积层,没有向量,所以称为 “全卷积”。

FCN 将第 6 层和 7 层分别从 4096 长度的向量转化为 4096 通道的卷积层,第 8 层则是 21 通道的卷积层。之所以第 8 层从 1000 缩减到 21,是因为 FCN 使用的识别库是 PASCAL VOC,在 PASCAL VOC 中有 20 种物体分类,另外一个 background 分类。(关于 PASCAL VOC 参见附录

再多说一句,以下(甚至全文)所用到的分割图片中不同的颜色就表示不同的物体类别,一共有 21 种颜色:

图像分类 语义分割 实例分割_卷积_14

CNN 的识别是图像级的识别,也就是从图像到结果,而 FCN 的识别是像素级的识别,对输入图像的每一个像素在输出上都有对应的判断标注,标明这个像素最可能是属于一个什么物体 / 类别。

在此处特别要指出的是,在实际的图像语义分割测试时,输入是一个 H*W*3 的三通道彩色图像,而输出是一个 H*W 的矩阵。

这就可以简单看做每一个像素所携带的信息是多维的,比如颜色,就分为 3 层,分别对应 R、G、B 三个值。(不知道什么是 RGB 的,鉴定为文科生,请迅速撤离,谢谢)

所以在进行卷积的时候,每一个通道都是要独立计算的,计算完之后再叠加,得到最终卷积层结果。

如果卷积核移动的步长为 1,那么卷积是按照像素排列去挨个计算的,计算量可想而知会有多么庞大。但是在实际中,相邻的像素往往都是一类,按照像素依次计算就显得冗余,所以在卷积之后会对输出进行一次池化(pooling)处理

那么什么又是池化呢?

来,我们再来看一张动图:

图像分类 语义分割 实例分割_卷积_15

池化简单来说就是将输入图像切块,大部分时候我们选择不重叠的区域,假如池化的分割块大小为 h*h,分割的步长为 j,那么一般 h=j,就像上图,如果需要重叠,只需要 h>j 即可。

对完整图像切分,再取切分区域中所有值的均值或最大值作为代表该区域的新值,放入池化后的二维信息图中。得到的新图就是池化结果。

在 CNN 和 FCN 的网络模型中,每一个卷积层,都包含了 [卷积 + 池化] 处理,这就是传说中的 “下采样”,但这样处理之后的结果是:图像的像素信息变小了,每一层的像素信息都是前一层的 1/2 大小,到第五层的时候,图像大小为原始图像的 1/32

在 CNN 算法里,这并没有什么要紧的,因为 CNN 最终只输出一个结果:“这个图上是个啥”,但是 FCN 不同,FCN 是像素级别的识别,也就是输入有多少像素,输出就要多少像素,像素之间完全映射,并且在输出图像上有信息标注,指明每一个像素可能是什么物体 / 类别。

所以就必须对这 1/32 的图像进行还原

这里用到个纯数学技术,叫 “反卷积”,对第 5 层进行反卷积,可以将图像扩充至原来的大小(严格说是近似原始大小,一般会大一点,但是会裁剪掉,为什么会大的原理略复杂,这里先不提,以后写进阶版再放进来)。

——这个 “反卷积” 称为 “上采样”。(和下采样对应)

图像分类 语义分割 实例分割_卷积_16

在技术上,我们可以对任一层卷积层做反卷积处理,得到最后的图像,比如用第三层 (8s-8 倍放大),第四层 (16s-16 倍放大),第五层 (32s-32 倍放大) 得到的分割结果。

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割_17

来看一张各层还原后的对比图,分别是:

图像分类 语义分割 实例分割_卷积_18

通过对比可以很明显看到:在 16 倍还原和 8 倍还原时,能够看到更好的细节,32 倍还原出来的图,在边缘分割和识别上,虽然大致的意思都出来了,但细节部分(边缘)真的很粗糙,甚至无法看出物体形状。

为什么会这样呢?

这里就涉及到一个感受域(receptive field)的概念。较浅的卷积层(靠前的)的感受域比较小,学习感知细节部分的能力强,较深的隐藏层 (靠后的),感受域相对较大,适合学习较为整体的、相对更宏观一些的特征

所以在较深的卷积层上进行反卷积还原,自然会丢失很多细节特征。

于是我们会在反卷积步骤时,考虑采用一部分较浅层的反卷积信息辅助叠加,更好的优化分割结果的精度:

图像分类 语义分割 实例分割_池化_19

尽管 FCN 的提出是一条很牛叉的路,但还是无法避免有很多问题,比如,精度问题,对细节不敏感,以及像素与像素之间的关系,忽略空间的一致性等问题。

于是更牛的大牛就出现了。

有牛人提出一种新的卷积计算方式,开始称为 “带 hole” 的卷积,也就是使用一种 “疏松的卷积核” 来计算,以此来取代池化的处理。

上面已经讲过,池化操作能够减少计算量,同时也能防止计算结果过拟合,那么单纯取消池化操作又会使单层网络的感受域缩小,但如果使用 “疏松的卷积核” 来处理卷积,可以达到在不增加计算量的情况下增加感受域,弥补不进行池化处理后的精度问题。

括弧:这种带洞的卷积方式后来起了一个高雅的名字叫做:“Dilated Convolutions”。

这种方式人为加大了卷积核内部元素之间的距离,可参考下图:

图像分类 语义分割 实例分割_卷积核_20

红点表示卷积核的元素,绿色表示感受域,黑线框表示输入图像。

a 为原始卷积核计算时覆盖的感受域,b 为当卷积核覆盖的元素间距离增大的情况,不再在连续的空间内去做卷积,跳着做,当这个距离增加的越大时,单次计算覆盖的感受域面积越大。

上图不太好理解的话再来看一张图:(个人觉得下面这个图非常好理解)

图像分类 语义分割 实例分割_池化_21

上层绿色点表示输入层像素点,下层黄色是输出层(单次计算时的层级关系),当卷积核元素间距为 0 时(相邻),123 对应输出 A,234 对应输出 B,345 对应输出 C,那么输出 ABC 三个元素结果的感受域只覆盖了 12345 这几个原始像素点。

如果采用稀疏的卷积核,假设间距为 1(相当于卷积计算时跳一个像素再取值计算),如图示,那么结果 A 对应的输入是 135,结果 B 对应的输入是 246,结果 C 对应的输入是 357,同样输出 ABC 三个结果,在原始图像上取的像素点的长度就多了。

这是水平 X 轴方向上的扩展,在 Y 轴上也会有同样的扩展,感受域在没有增加计算(相对于池化操作后)的情况下增大了,并且保留了足够多的细节信息,对图像还原后的精度有明显的提升。

看一下对比图:

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割_22

第一列是原始图像,最后一列是手工标注的训练输入图像,第二列为 FCN 在 1/8 倍数下的还原,第三列则是采用了新的卷积算法的还原图像,可以很明显看到,第三列对细节的分割明显优于第二列 FCN 8 倍的图像。

刚才还提到了第二个问题,即像素与像素之间的逻辑关系的问题,毕竟前面再牛叉的算法也只是单纯的计算没有根据物理意义进行判断在输出的标注里这些结果是否合法(符合现实逻辑)。

很多以深度学习为框架的图像语义分割系统都使用了一种叫做 “条件随机场”( Conditional Random Field,简称 CRF)的技术作为输出结果的优化后处理手段。其实类似技术种类较多,比如还有马尔科夫随机场 (MRF) 和高斯条件随机场 (G-CRF) 用的也比较多,但原理都较为类似。

简单来介绍一下 “条件随机场” 的概念。

FCN 是像素到像素的影射,所以最终输出的图片上每一个像素都是标注了分类的,将这些分类简单地看成是不同的变量,每个像素都和其他像素之间建立一种连接,连接就是相互间的关系。

于是就会得到一个 “完全图”:

图像分类 语义分割 实例分割_卷积_23

上图是以 4*6 大小的图像像素阵列表示的简易版。

那么在全链接的 CRF 模型中,有一个对应的能量函数:

图像分类 语义分割 实例分割_卷积_24

嗯,不要问我这个公式里各种符号是啥,我看不懂。但是我知道这个公式是干嘛滴:

其中等号右边第一个一元项,表示像素对应的语义类别,其类别可以由 FCN 或者其他语义分割模型的预测结果得到;而第二项为二元项,二元项可将像素之间的语义联系 / 关系考虑进去。

这么说太抽象,举个简单的例子,“天空”和 “鸟” 这样的像素在物理空间是相邻的概率,应该要比 “天空” 和 “鱼” 这样像素相邻的概率大,那么天空的边缘就更应该判断为鸟而不是鱼(从概率的角度)。

通过对这个能量函数优化求解,把明显不符合事实识别判断剔除,替换成合理的解释,得到对 FCN 的图像语义预测结果的优化,生成最终的语义分割结果。

优化后的对比图:

图像分类 语义分割 实例分割_卷积_25

上图第二列是 FCN 网络 8 倍还原分割结果,第三列是将 CRF 植入 FCN 处理后的结果。

可以很明显的看到,第三列的物体识别无论是轮廓细节分割还是物体识别,都优于第二列,特别是第二行的沙发中有奇怪的红色东西的识别,在进行 CRF 优化之后,还原成了绿色的沙发。

OK,说了这么多,终于快要讲完了(好累)。

以上就是目前较为前沿的图像语义分割技术。

目前的这种机器学习方式还属于监督性学习,牛叉闪闪的科学家们还是希望将来可以实现半监督或弱监督式学习,这样更类似人类的学习认知方式。

在这条道路上,还有很多有趣的东西,比如示例级别(instance level)的图像语义分割问题也同样热门。

该类问题不仅需要对不同语义物体进行图像分割,同时还要求对同一语义的不同个体进行分割(例如需要对图中出现的九把椅子的像素用不同颜色分别标示出来)。

图像分类 语义分割 实例分割_图像分类 语义分割 实例分割_26

另外,在目前的计算技术水平下(硬件软件),使用 FCN 训练建模的时间大约需要三周,这也说明在这个领域里还有很多值得探索和需要解决的问题。

对此有兴趣的同学们自己去继续研究吧,哈哈。

曾有一个业界大牛说过这样一段话,送给大家:

“华人在计算机视觉领域的研究水平越来越高,这是非常振奋人心的事。我们中国错过了工业革命,错过了电气革命,信息革命也只是跟随状态。但人工智能的革命,我们跟世界上的领先国家是并肩往前跑的。能身处这个时代浪潮之中,做一番伟大的事业,经常激动的夜不能寐。”

AI 的浪潮即将席卷而来,你,准备好了么?