4.1 计算机视觉

1.先聊聊模型眼里的图是个什么

说起来,这一章我们开始聊计算机视觉(Computer Vision)。在模型眼里,一张图到底是个什么?其实它就是一张带着空间位置的数字网格,每个小格子里装着一个颜色数值。还记得吧,前面几章我们反复提到,模型说穿了就是一个函数,你给它输入 xx,它返回输出 yy。视觉模型的输入 xx,就是这一整张数字网格。

那么视觉模型要做的第一件事,就是把这些零散的像素,组织成稍微有点意义的表示。这个过程是分层的,先从一小块一小块的局部里抓出边缘和纹理,再把一个个局部的小模式拼成形状,最后才拼成那种一眼能认出来的物体。这个过程蛮像我们看远处的风景。我之前翻过一本讲印象派绘画的画册,里头提到人眼辨认同一个场景,往往也是先捕捉大块的色块和明暗,再慢慢分辨出树、房子、人的轮廓,最后才认出具体的对象。视觉模型走的差不多也是这条路子,一层层地把零碎的局部证据往上汇拢。

这种一层一层往上拼的本事,靠的就是卷积结构。卷积有两个特别对胃口的脾气,一个是局部连接(每次只盯着图里的一小块看),另一个是参数共享(同一种特征检测器在整张图上来回滑动着复用)。这俩脾气正好踩中了图像本身的空间规律,所以卷积在视觉任务里长期担任主力位置。这一章我们就来看看,一个训练好的视觉模型到底都能干些什么活。

2.分类、检测和分割这三种活儿

视觉任务有好几种,目标不一样,模型最后吐出来的东西也不一样。

最基础的一种叫图像分类,它给整张图打一个类别标签。你给模型一张照片,让它判断里面是猫还是狗,模型最后吐出来的是一串类别分数,分数最高的那一类就是它的判断。这个活儿最朴素,但也最常用。比方说相册里那种自动把照片分成风景、美食、自拍的玩法,底下跑的就是分类。电商里识别商品主图属于哪个类目,用的也是同一套思路。

目标检测要更进一步,它不光要说图里有什么,还要说出这些东西分别在哪个位置。模型这回吐出来的是一组带着位置的框,每个框圈住一个目标,再给每个框配上一个类别。比如一张街景照片,模型会把街上所有的车和行人都框出来,还要标清楚每个框到底是车还是人。自动驾驶里那种实时识别路牌和行人的功能,干的就是这个活儿。

再细一档的是分割,它要把活儿干到像素级别。语义分割给图里的每一个像素都分一个类别,相当于把整张图按类别重新涂成一片片颜色块。实例分割更细致一些,它不光要分出像素属于哪一类,还得把同一类里不同的个体也给分开。比如画面里有三只猫,它得标清楚哪一块像素属于第一只、哪一块属于第二只、哪一块属于第三只,不能糊成一团。这种活儿标注起来相当费工夫,成本也跟着水涨船高。

任务越往下越细,模型要输出的东西就越多越复杂,对数据标注的要求也越高。

3.迁移学习,站在巨人肩膀上接着练

视觉数据标注起来成本相当高。给几万张图一个个人工地标框、标像素,又慢又烧钱,普通的研究者和小团队往往吃不消。迁移学习就提供了一个特别省钱的法子。

那些在超大数据集(比如ImageNet那种上千万张图的量级)上预训练过的视觉模型,早就把边缘、纹理、形状这些通用的视觉表示学到手了,家底厚实得很。你现在要做个新任务,比如识别校园里不同的建筑,可以直接拿这种预训练模型当起点,在它的基础上只用少量你自己新拍的新数据接着练,往往就能拿到一个相当不错的效果。

这件事如果从头自己训一个,得自己准备几十万张标好的图,租GPU跑上好几天,又费时间又费钱,最后还未必能比人家预训练过的强。用了迁移学习,等于站在巨人肩膀上接着练就行。当然啦,迁移过来的效果到底好不好,要看原来预训练的任务跟你的新任务像不像,以及你手头新数据的规模和质量。两个任务越接近、新数据越扎实,迁移过来的红利就越大。

记得我看过一本讲现代医学影像的书,里头讲到不少医院做肺结节筛查模型,往往会直接拿在自然图像上预训练过的网络作起点,再用自己的少量CT影像接着练,省去从零开始训练的工夫。一来数据量小养得起,二来收敛也快,这就是迁移学习很典型的用法。小张之前做个识别校园植物的小项目,只有几百张自己拍的照片,靠一个预训练的ResNet接着练,一个下午就跑出了能用的结果,要是真从零训,这点数据根本喂不饱网络。

4.怎么评价一个视觉模型行不行

模型训完了到底行不行,得拿尺子量一量。可面对不同的任务,就得换不同的尺子。

类别分布比较均衡的分类任务,光看准确率(也就是猜对的比例)就够了。可一旦类别很不均衡,这个数就水分很大。比如你做一个识别狗的模型,100张图里99张都是猫只有1张狗,那你哪怕写一个永远只猜猫的模型,准确率都能飙到99%,看着漂亮其实没什么用。这时候就得换更细的指标。

精确率盯的是,模型说是狗的那些里头,真正是狗的占多少。召回率盯的是,所有真正的狗里头,被模型揪出来的占多少。这俩经常一个高另一个就低,得看你的任务怎么取舍。比如你做医院的肿瘤初筛,宁可多筛出几个假的也别漏掉真的,那就更看重召回率。反过来你做门口闸机刷脸放行,宁可慢一点多核一次也别错放陌生人,那就更看重精确率。F1分数则把这俩综合成一个数,省得你来回盯着俩数看。

要把这些指标实打实地算出来,得先有一张表,它叫混淆矩阵。这名字听着挺唬人,其实就是一张方表,专门用来记录模型在每一类上猜对了几次、又把谁错认成了谁。约定俗成的画法是,表的每一行对应真实类别,每一列对应预测类别,行和列的类别顺序保持一致。沿着左上到右下那条主对角线排开的格子,全都是模型猜对的,剩下那些偏离对角线的格子,全都是模型犯糊涂把一类认成另一类的记录。

我们还是拿猫狗两类接着举例。这张表里有四个关键格子,行家们给它们各起了一个专门的名字。真实是狗、模型也猜狗的,叫真阳性(True Positive,记作 TP\mathrm{TP})。真实是狗、模型却猜成猫的,叫假阴性(False Negative,记作 FN\mathrm{FN}),这就是漏检。真实是猫、模型却猜成狗的,叫假阳性(False Positive,记作 FP\mathrm{FP}),这就是误报。真实是猫、模型也猜猫的,叫真阴性(True Negative,记作 TN\mathrm{TN})。这四个缩写接下来会反复登场,先跟它们混个脸熟。

有了这四个数,准确率、精确率、召回率、F1分数全都能直接套公式。准确率就是所有猜对的除以总数:

Accuracy=TP+TNTP+TN+FP+FN\mathrm{Accuracy}=\frac{\mathrm{TP}+\mathrm{TN}}{\mathrm{TP}+\mathrm{TN}+\mathrm{FP}+\mathrm{FN}}

精确率(Precision)用 TP\mathrm{TP} 除以模型所有猜狗的次数:

Precision=TPTP+FP\mathrm{Precision}=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FP}}

召回率(Recall)用 TP\mathrm{TP} 除以所有真实狗的个数:

Recall=TPTP+FN\mathrm{Recall}=\frac{\mathrm{TP}}{\mathrm{TP}+\mathrm{FN}}

而F1分数是精确率和召回率的调和平均:

F1=2×Precision×RecallPrecision+Recall\mathrm{F1}=2\times\frac{\mathrm{Precision}\times\mathrm{Recall}}{\mathrm{Precision}+\mathrm{Recall}}

调和平均有一个脾气,就是它特别容易被那个比较小的数拽下去。所以精确率和召回率哪个偏低,F1就跟着偏低,光靠另一个硬撑是糊弄不过去的。回到前面那个99张猫1张狗的极端例子,那个永远猜猫的模型把唯一的狗也猜成猫,TP=0\mathrm{TP}=0,精确率和召回率双双归零,F1也是 00,这才能把它的不足如实暴露出来。所以你看,类别越不均衡,越要盯着精确率、召回率、F1这些细指标,光看准确率分分钟被误导。

检测和分割这种带位置的任务,还得额外看位置准不准。模型预测出来的框或者像素区域,跟人工标的真实位置重合了多少,是评价这类活儿的重要依据,这个重合度有个专门的名字叫交并比(Intersection over Union,缩写IoU)。它的算法是预测框和真实框的交集面积,除以它俩的并集面积:

IoU=交集面积并集面积\mathrm{IoU}=\frac{\text{交集面积}}{\text{并集面积}}

这个比值越大,说明模型框得越准。举个例子,真实框面积是 100100,预测框面积也是 100100,它俩重合的交集面积是 8080,那么并集面积就是 100+10080=120100+100-80=120,算下来 IoU=80/1200.67\mathrm{IoU}=80/120\approx0.67。一般来说 IoU\mathrm{IoU} 超过 0.50.5 就算框得还能看,超过 0.70.7 就是框得相当准了,没把猫的框给框到狗身上去。

光看一张图一个框的 IoU\mathrm{IoU} 还不够,整批图的整体表现怎么样,得有一个汇总的数。这里就轮到平均精度(Average Precision,缩写AP)出场。把模型在某一类上、按置信度从高到低依次排出来的所有预测,画成一条精确率随召回率变化的曲线,曲线下方的面积就是AP,它把这两个指标在不同取值下的综合表现压成了一个数。再把所有类别的AP求一个平均,就是大家常说的平均精度均值(mean Average Precision,缩写mAP)。一个mAP的数,就把模型在多个类别上的整体检测水平给概括了,所以它基本是目标检测里必报的核心指标。

这里还有一个小坑要提一嘴。算mAP的时候,得先定一个 IoU\mathrm{IoU} 阈值,只有 IoU\mathrm{IoU} 高于这个阈值的框才算模型抓对了。阈值卡得越严(比如从 IoU=0.5\mathrm{IoU}=0.5 提到 IoU=0.75\mathrm{IoU}=0.75),框得稍微歪一点就不算数,mAP自然就往下掉。所以看论文里人家报mAP,往往会注明阈值取了多少,对着阈值一起看才有意义,不然就是各说各的。

5.数据增强,凭空给模型变出更多训练样本

数据是深度学习的命根子,模型想要表现好,离不开足够多、足够丰富的训练图。可现实里你手头往往就那么几百张图,又哪有那个闲钱去雇人标几万张。数据增强就是给数据扩容的便宜法子,说白了就是对已有的图片做点手脚,凭空造出一批看起来不太一样的新样本,省去到处收集新图的麻烦。

最常用的招数有这么几个。水平翻转就是把图左右镜像一下,一只朝左走的猫翻转完就朝右走,对模型来说这就是个全新的样本。随机裁剪是从原图里随机抠出一小块,每次抠的位置都不太一样,这一抠等于把同一张图变出好几个版本。颜色调整就更花式了,调一调亮度、对比度、饱和度,或者把色调稍微拧一拧,照片的观感立马变样。旋转、缩放、加噪声这些手法也都能往上堆,能玩的招挺多。

这些招数管用的道理也很朴素。一张猫的照片,朝左走的猫和朝右走的猫,对人来说一眼就是同一只猫,可对模型来说像素排列完全不一样,得分别喂过它才学得会朝向跟类别没什么关系这一层道理。数据增强就是在变着法子把这个道理灌输给模型,逼着它别去死记原图里那些无关紧要的细节,比如这只猫恰好永远朝左、恰好蹲在草坪正中央。这么一折腾,模型见的样本表面上千变万化,本质规律却始终如一,它就更可能学到那种真正起作用的、跨样本通用的特征,泛化到没见过的新图上自然就稳得多。

这件事有点像运动员练基本功。我看过一部讲女排训练的纪录片,里头教练让队员反复接各种角度、各种力道的扣球,平时见过的花样越多,赛场上遇到陌生的球路就越不慌。我有个朋友小时候练乒乓球,教练发球时刻意变着旋转和落点,道理也是一样,把多样性留在训练里,把确定性留到比赛时。模型其实也遵循同样的逻辑,增强出来的多样性,最后都化成了它应对新场景的底气。

不过数据增强也得讲分寸,招数堆得越多未必越管用,乱来一通反而容易翻车。比如做数字识别这种活儿,把一个6上下翻转一下就成了9,标签跟内容对不上,模型当场就糊涂了。所以朝向无关的任务可以随便翻,朝向本身就携带信息的任务,那就老老实实别瞎翻。增强的手法得尊重任务本身的性质,这一点心里得有数。

练习

Q1. 精确率和召回率分别盯的是什么?做一个医院肿瘤初筛模型,更看重哪个?

精确率盯的是模型说是狗(阳性)的那些里,真正是狗的占多少,即 TP/(TP+FP)\mathrm{TP}/(\mathrm{TP}+\mathrm{FP});召回率盯的是所有真正的狗里,被模型揪出来的占多少,即 TP/(TP+FN)\mathrm{TP}/(\mathrm{TP}+\mathrm{FN})。肿瘤初筛宁可多筛出几个假的也别漏掉真的,所以更看重召回率,把漏检(假阴性)压到最低。

Q2. 真实框面积是 100,预测框面积也是 100,两者重合的交集面积是 80,IoU 是多少?框得算准吗?

并集面积是 100+10080=120100+100-80=120,IoU=80/1200.67=80/120\approx0.67。一般来说 IoU 超过 0.5 算还能看,超过 0.7 算框得相当准,0.67 处在两者之间,框得还算靠谱。

Q3. 做数字识别时能不能把图上下翻转当数据增强?类别很不均衡时为什么光看准确率会被骗?

不能。把一个 6 上下翻转就成了 9,标签跟内容对不上,模型当场就糊涂。这类朝向本身就携带信息的任务,增强手法得尊重任务性质,不能瞎翻。类别很不均衡时光看准确率水分很大:比如 100 张图里 99 张猫 1 张狗,一个永远只猜猫的模型准确率都能飙到 99%,看着漂亮其实没用。这时得换精确率、召回率、F1 这些细指标,比如那个永远猜猫的模型 TP=0\mathrm{TP}=0,精确率和召回率双双归零,F1 也是 0,才能把不足如实暴露出来。

相关标签
深度学习计算机视觉图像