作者:Billy Z
转载自:PaperWeekly
编辑:一点人工一点智能
原文:如何给一个端到端的分类神经网络模型退出先验常识?
01 模型退出先验常识的必要性
端到端的深度神经网络是个黑盒子,尽管可能主动学习到一些可区分度好的特色,然而往往会拟合到一些非重要特色,导致模型会部分坍塌到一些不好的特色下面。经常一些人们想让模型去学习的特色模型反而没有学习到。
为了解决这个问题,给模型退出人为设计的先验信息会让模型学习到一些要害的特色。上面就从几个方面来谈谈如何给模型退出先验信息。
为了不便展现,我这边用一个简略的分类案例来展现如何把先验常识退出到一个具体的 task 中。咱们的 task 是在所有的鸟类中辨认出一种萌萌的鹦鹉,这中鹦鹉叫鸮(xiāo)鹦鹉,它长成上面的样子:
鸮(xiāo)鹦鹉
这种鸟有个特点:
就是它可能呈现在任何中央,但就是不可能在天上,因为它是世界上惟一一种不会飞的鹦鹉(不是惟一一种不会飞的鸟)。
好,介绍完 task 的背景,咱们就能够分分钟搭建一个端到端的分类神经网络,能够抉择的网络结构能够有很多,如 resnet, mobilenet 等等,loss 往往是一个罕用的分类 Loss,如穿插熵,高级一点的用个 focal loss 等等。确定好了最优的数据(扰动形式),网络结构,优化器,学习率等等这些之后,往往模型的精度也就达到了一个下限。
而后你测试模型发现,有些艰难样本始终分不开,或者是一些简略的样本也容易分错。这个时候如果你还想晋升网络的精度,能够通过给模型退出先验的形式来进一步晋升模型的精度。
02 基于 pretrain 模型给模型退出先验
给模型退出先验,大家最容易想到的是把网络的 weight 替换成一个在另外一个工作上 pretrain 好的模型 weight。通过的预训练的模型(如 ImageNet 预训练)往往曾经具备的辨认到一些根本的图片 pattern 的能力,如边缘,纹理,色彩等等,而辨认这些信息的能力是辨认一副图片的根底。如下图所示:
但这些先验信息都是一些比拟 general 的信息,咱们是否能够退出一些更加 high level 的先验信息呢。
03 基于输出给模型退出先验
如果你有这样的一个先验:
你感觉鸮鹦鹉的头是一个区别其余它和鸟类的重要局部,也就是说相比于身材,它的头部更能辨别它和其余鸟类。
这时怎么让网络更加关注鸮鹦鹉的头部呢。这时你能够这样做,把整个鸮鹦鹉和它的头部作为一个网络的两路输出,在网咯的后端再把两路输出的信息交融。以达到既关注局域,又关注整体的目标。一个简略的示意图如下所示。
04 基于模型重现给模型退出先验
接着下面的设定来,如果说你感觉给模型两路输出太麻烦,而且减少的计算量让你感觉很不爽。
这时,你能够尝试让模型本人发现你设定的先验常识。
如果说你的模型能够本人输入鸟类头部的地位,尽管这个鸟类头部的地位信息是你不须要的,然而输入这样的信息代表着你的网络可能 locate 鸟类头部的地位,也就给鸟类的头部更加多的 attention,也就相当于给把鸟类头部这个先验信息给加上去了。
当然间接模拟 detection 那样去回归出地位来这个工作太 heavy 了,你能够通过一个生成网络的支路来生成一个鸟类头部地位的 Mask,一个简略的示意图如下:
测试的时候不减少计算量
05 基于 CAM 图激活限度给模型退出先验
针对鸮鹦鹉的分类,我在下面的提到一个十分有意思的先验信息:
那就是鸮鹦鹉是世界上惟一一种不会飞的鹦鹉。
这个信息从侧面来说就是,鸮鹦鹉所有中央都可能呈现,就是不可能呈现在天空中(当然也不可能呈现在水中)。
也就是说岂但鸮鹦鹉自身是一个分类的重点,鸮鹦鹉呈现的背景也是分类的一个重要参考。如果说背景是天空,那么就肯定不是鸮鹦鹉,同样的,如果说背景是淡水,那么也肯定不是鸮鹦鹉,如果说背景是北极,那么也肯定不是鸮鹦鹉,等等。
也就是说,你不能通过背景来判断一只未知的鸟是鸮鹦鹉,然而你能通过背景来判断一只未知的鸟必定不是鸮鹦鹉(是其余的鸟类)。
所以如果说获取了一张输出图片的激活图(蕴含背景的),那么这张激活图的鸟类身材局部必定蕴含了鸮鹦鹉和其余鸟类的激活,然而鸟类身材外的背景局部只可能蕴含其余鸟类的激活。
所以具体的做法是基于激活图,通过限度激活图的激活区域,退出指标先验。
CAM [1] 激活图是基于分类网络的倒数第二层卷积层的输入的 feature_map 的线性加权,权重就是最初一层分类层的权重,因为分类层的权重编码了类别的信息,所以加权后的响应图就有了基于不同类别的区域相应。
具体的介绍能够看:
https://zhuanlan.zhihu.com/p/51631163
具体的激活图生成形式能够如下示意:
说了这么多,上面就展现展现激活图的样子:
大家能够看到,下面一张是一只鸮鹦鹉的激活图,上面是一只在天空翱翔的大雁的激活图。
因为鸮鹦鹉的 Label 是 0,其余鸟类的 Label 是 1,所以在激活图上,只有是负值的激活区域都是鸮鹦鹉的激活,也就是 Label 为 0 的激活,只有是正值的激活都是其余鸟类的激活,也就是 Label 为 1 的激活。
为了不便展现,我把负值的激活用冷色调来显示,把正值的激活用暖色调来显示,所以就是变成了下面两幅激活图的样子。而左边的数字是具体的激活矩阵(把激活矩阵进行 GAP 就能够变成最终输入的 Logits)。
到这里不晓得大家有没有发现一个问题,就是无论对于鸮鹦鹉还是大雁的图片,它们的激活图除了散布在鸟类自身,也会有一部分散布在背景上。对于大雁咱们好了解,因为大雁是飞在天空中的,而鸮鹦鹉是不可能在天空中的,所以天空的正激活是十分正当的。然而对于鸮鹦鹉来说,其在鸟类身材以外的负激活就不是太正当,因为,大雁或者是其余的鸟类,也可能在鸮鹦鹉的高空栖身环境中(然而鸮鹦鹉却不可能在天空中)。
所以环境不能提供任何证据来证实这一次鸟类是一只鸮鹦鹉,鸮鹦鹉的负激活只是在鸟类的身材上是正当的。而其余鸟类的正激活却能够同时在鸟类身材上又可能在鸟类的背景上(如天空或者陆地)。
所以咱们须要这样建模这个问题,就是在除鸟类身材的背景上,不能呈现鸮鹦鹉的激活,也就是说不能呈现负激活(Label 为 0 的激活)。所以上面的激活才是正当的:
从下面来看,在除鸟类身材外的背景局部是不存在负激活的,尽管下面的背景局部有一些正的激活(其余鸟类的激活),然而从左边的激活矩阵来看,负激活的 scale 是占据绝对优势的,所以齐全不会烦扰对于鸮鹦鹉的判断。
所以问题来了,怎么从网络设计方面来达到这个目标呢?
其实能够从 Loss 设计方面来达到这个成果。咱们假如每一个鸟都有个对应的 mask,mask 内是鸟类的身材局部,mask 外是鸟类的背景局部。那么咱们须要做的就是克制 mask 外的背景局部激活矩阵的负值,把那一部分负值给克制到 0 即可。
鸟类的激活矩阵和 mask 的关系如下图(红色的曲线代表鸟的边界 mask):
咱们的 Loss 设计能够用上面的公式示意:
具体的网络的 framework 能够如下所示:
其中虚线局部只是训练时候须要用到,inference 的时候是不须要的,所以这种办法也是不会占用任何在 inference 前向时候的计算量。
06 基于辅助学习给模型退出先验常识
到当初为止,咱们还只是把咱们的鸟类分类的 task 当成一个二分类来解决,即鸮鹦鹉是一类,其余的鸟类是一类。
然而咱们晓得,世界的鸟类可不仅仅是两类,除了鸮鹦鹉之外还有很多品种的鸟类。而不同鸟类的特色或者有很大的差异,比方鸵鸟的特色就是脖子很长,大雁的特色就是翅膀很大。
如果只是把鸮鹦鹉当做一类,把其余的鸟类当做一类来学习的话,那么模型很可能不能学到能够利用的辨别非鸮鹦鹉的特色,或者是会坍塌到一些区分度不强的特色下面,从而没有学到可能很好的辨别不同其余鸟类的特色,而那些特色对去区别鸮鹦鹉和其余鸟类或者是重要的。
所以咱们有必要退出其余鸟类存在不同类别的先验常识。而这里,我次要介绍基于辅助学习的形式去学习相似的先验常识。首先我要解释一下什么是辅助学习,以及辅助学习和多任务学习的区别:
上图的左侧是多任务学习的例子,右侧是辅助学习的例子。左侧是个典型的 face attribute 的 task,意思是输出一张人脸,通过多个 branch 来输入这一张人脸的年龄,性别,发型等等信息,各个 branch 的工作是独立的,同时又共享同一个 backbone。
左边是一个典型的辅助学习的 task,意思是出入一张人脸,判断这一张人脸的性别,同时另外开一个(或几个)branch,通过这个 branch 来让网络学一些辅助信息,比方发型,皮肤等等,来帮忙网络主工作(分男女)的判断。
好,回到咱们的鸮鹦鹉分类的 task,咱们可能首先会想到上面的 Pipeline:
这样尽管能够把不同类别的鸟类的特色都学到,然而却减弱了网络对于鸮鹦鹉和其余鸟类特色的别离。
通过试验发现,这种网络架构不能很好的减少主工作的分类精度。为了充沛的学到鸮鹦鹉和其余鸟类特色的别离,同时又能带入不同品种鸟类类别的先验,咱们引入辅助工作:
在下面的 Pipeline 中,辅助工作相比如主工作,把其余鸟类做更加粗疏的分类。这样网络就学到了辨别不同其余鸟类的能力。
然而从试验成果来看这个 Pipeline 的精度并不高。通过剖析起因,发现在主工作和辅助工作外面都有鸮鹦鹉这一类,这样当回传梯度的时候,相当于把辨别鸮鹦鹉和其余鸟类的特色回传了两次梯度,而回传两次梯度显著是没用的,而且会烦扰辅助工作学习不同其余鸟类的特色。
所以咱们能够把辅助工作的鸮鹦鹉类去除,于是便造成了上面的 pipeline:
通过试验发现,这种 pipeline 是有利于主工作精度晋升的,网络对于特色显著的其余鸟类的分类能力失去了肯定水平的晋升,同时对于艰难类别的分类能力也有肯定水平的晋升。
当然,辅助工作的 branch 能够不只是一类,你能够通过多个类别来定义你的辅助工作的 branch:
这时候你会想,下面的 pipeline 好是好,然而我没有那么多的 label 啊。是的,下面的 pipeline 除了主工作的 label 标注,它还同时须要很多的辅助工作的 label 标注,而标注 label 是深度学习工作外面最让人头疼的问题(之一)。
别怕,我上面介绍一个 work,它基于 meta-learning 的办法,让你不再为给辅助工作标注 label 而懊恼,它的 framework 如下:
这个 framework 采纳基于 maxl [2] 的计划(https://github.com/lorenmt/maxl),辅助工作的数据和 label 不是由人为手工划分,而是由一个 label generator 来产生,label generator 的优化指标是让主网络在主工作的 task 上的 loss 升高,主网络的指标是在主工作和辅助工作上的 loss 同时升高。
然而这个 framework 有个毛病,就是训练工夫会回升一个数量级,同时 label generator 会比拟难优化。感兴趣的同学能够本人尝试。然而不得不说,这篇文章有两个论断倒是很有意思:
- 假如 primary 和 auxiliary task 是在同一个 domain,那么 primary task 的 performance 会进步当且仅当 auxiliary task 的 complexity 高于 primary task。
- 假如 primary 和 auxiliary task 是在同一个 domain,那么 primary task 的最终 performance 只依赖于 complexity 最高的 auxiliary task。
07 结语
先总结一下所有能够无效的退出先验信息的框架:
你能够通过上述框架的抉择来退出本人的先验信息。
给神经网络的黑盒子外面退出一些人为设定的先验常识,这样往往能给你的 task 带来肯定水平的晋升,不过具体的 task 须要退出什么样的先验常识,须要如何退出先验常识还须要本人摸索。
参考文献:
[1] CAM https://arxiv.org/abs/1512.04150
[2] maxl https://arxiv.org/abs/1901.08933