YOLO v1/v2/v3/v4

  YOLO v1-v3的作者,Joseph Redmon大神,因为考虑到自己的研究成果会被用于军事用途和个人隐私领域,因此在2020年2月宣布退出CV界,可谓是非常洒脱了。但YOLO系列并没有因此停止更新,在随后的4月,YOLO v4由他人接棒发表并得到了大神本人的认可。全文涉及到非常多的detection领域的历史研究成果,可谓是集大成者,一开始初看简直是眼花缭乱,也真心感叹现在水论文越来越不容易了。为了理解这篇paper也补看了很多相关的历史paper,中间又断断续续地受到疫情和毕业手续的影响,现在终于能静下心来好好地记录一下相关的知识。全文涵盖的知识点比较多且杂,但也是成体系的,久远的YOLO v1-v3会一带而过,重点放在v4上(李鬼版的v5请忽略)。


  • YOLO v1(CVPR 2016)

  早在关于ThunderNet的一文中,就已经对YOLO v1的工作进行了记录。
  它的优点在于,第一次把detection这样的任务用端到端的形式来完成,能达到很高的计算速度。   它的缺点在于:一是网络中存在全连接层,这样与空间位置相对应的信息会被打乱,localization会受影响,因此它的框位置误差很大;二是划分成7x7的网格后每个网格只预测B=2个候选框,数量这么少会有很快的计算速度,但这导致了很低的召回率,会漏掉很多小目标(如密集的鸟群场景),另外由于缺少特定长宽比的候选框(如Faster-RCNN中的9种指定长宽比的候选框),缺少了这部分的先验知识,对于极端长宽比的物体检测效果会很差(如细长的领带);三是计算loss所用的参考量(x,y,w,h)没有归一化,此时“大框的小误差”和“小框的大误差”的损失值几乎相同,但是后者对精度的提升明显更重要。

原文地址:You Only Look Once: Unified, Real-Time Object Detection


  • YOLO v2(CVPR 2017)

  v2在v1的基础上,分别针对训练trick(Better)、网络结构本身(Faster)、数据集(Stronger)三个方向做了改进。

训练trick(Better)

  – 使用了BN。
  – v1的backbone在ImageNet上预训练时,输入尺寸是224x224,而迁移到detection任务后输入尺寸变成了448x448,这之间的转变太过突然。为此,v2在预训练时先在448x448的尺寸上跑了10个epoch作为过渡,这样能涨4个点。这提醒我们,不仅train和inference时要保持前后一致,pre-train和fine tune也需要保持一致。
  – 去掉了v1中的全连接层;输入从448x448改为奇数的416x416,以方便取几何中心;取更大的feature(13x13,v1中为7x7)来作为最终的特征层;抛弃v1中的anchor free,重拾anchor box,使得召回率有所提升。
  – 为了给予合理的检测框先验信息,使用k-means聚类来对VOC和COCO数据集中的标签框进行分析,得出了k=5时的几种常见框尺寸,使得无需手动挑选候选框。
  – 坐标值采用归一化后的有限相对值,提升模型训练的稳定性。v1中的坐标值是绝对值(没有归一化)缺乏对小框的关注,RPN中的坐标值是相对值(但没有对范围做限制)在模型训练初期具有不稳定性,v2则吸取两种方法的优缺点,预测坐标相对于grid cell的相对偏移量,这种偏移还经过归一化处理,不会超过0-1的范围。
  – 融合最后的13x13和倒数第二层的26x26的多尺度feature,兼顾大目标和小目标。
  – 每10个batch变换一次输入图片尺寸,从最小的320x320逐渐变到到最大的608x608,提升模型对多尺度目标的检测能力。由于网络中不含全连接层,因此训练时可采用不同大小的尺寸。

网络结构(Faster)

  可能是大佬为了推广自己写的框架Darknet,v2的backbone并没有采用VGG,而是自定义了一个很朴素的网络,命名为Darknet-19,flops要比VGG小。整体看来平平无奇。

数据集(Stronger)

  数据比模型更重要。ImageNet的建立为分类网络的不断突破提供了平台,但在detection任务上,标数据更为繁琐,一张图片可能有很多个物体,每个物体的种类及边界框都需要标出来,工作量还是很大的,因此现有的detection公开数据集(PASCAL VOC、MSCOCO、ImageNet Det等)规模远不及classification数据集(ImageNet等)。那么有没有办法把classification数据集也利用起来?毕竟它们虽然没有提供坐标信息,但是也提供了类别信息,这部分类别信息能够显著拓展检测的类别数。
  根据这种思想,v2将detection数据集和classification数据集融合起来。当输入是detection数据时,按照正常的训练过程进行反向传播;当输入是残缺的classification数据时,只计算和更新类别对应的loss和网络参数。   难点在于,如何对数据集进行融合?如上图,用于detection的COCO数据集和用于classification的ImageNet都是属于摊大饼型的结构,每一个类别之间地位平等且相互排斥。但两个数据集之间存在交叉部分,同时由于ImageNet的细粒度分类很全,例如“英短蓝白猫”、“英短金渐层”同属于“英短猫”,“英短猫”又属于“猫”,“猫”又属于“动物”,动物又属于“物体”。因此采用层级的树状关系图来处理融合后的数据比较合理。
  文中将COCO和ImageNet融合后,按照树状图的关系处理,得到具有1396个节点的树。针对每一个anchor,预测出长度为1396的矢量,对该矢量按照层级关系进行同层级的softmax得到条件概率,根据全概率公式连乘即可得到所属类别的条件概率。   经过这种弱监督式的融合数据集训练后,YOLO v2得以检测超过9000种类别,因此得名为YOLO 9000。

  总结一下,v2的主要特点在于使用了融合数据集,一下子拓展了可检测的类别范围。至于网络结构和训练trick,感觉算是小的改进和调参吧。
  原文地址:YOLO9000: Better, Faster, Stronger


  • YOLO v3(2018)

  v3是以会议报告的形式发表的,所以写作比较随意。主要的改进是吸收了ResNet残差连接、FPN多尺度特征的思想,对网络结构进行了修改,其它更多的是一些有利于工程化的trick。

网络结构

  类似于v2中的Darknet-19,但是加入了skip connection后,网络得以变得更深,共有53层,故取名为Darknet-53。
  在backbone后加入FPN,在三个尺度上进行检测(这里图方便盗个图,出处在知乎的一篇博客)。

训练trick

  – 类似于v2,对数据集的标签框进行聚类,但是这里取k=9,得到如下的先验框尺寸:(10×13),(16×30),(33×23),(30×61),(62×45),(59×119),(116 × 90),(156 × 198),(373 × 326)。
  – 放弃了在v2中使用的多层级softmax,因为作者认为用这种方法求得各个类别的概率其实效果不好,转而采用独立的logistic classifier分类器进行分类。
  – 把anchor box分成三类:正例,与任一ground truth之间的IoU最高的视为正例,可用来计算置信度、检测框、类别loss;负例,与所有ground truth之间的IoU都小于阈值(0.5)视为负例,不用于计算loss;忽略例,除去正例后,与任一ground truth之间的IoU大于阈值(0.5)视为忽略例,不用于计算loss。
  – 检测框loss采用MSE,类别loss采用BCE,置信度loss采用BCE。
  总结一下,v1中小目标召回率低的问题,在v3中由于加了带先验的anchor,已经得到了较好的解决;但是在localization的问题上依然有所欠缺,这算是one-stage方法固有的缺陷吧,不过速度依然是快的飞起。
  原文地址:YOLOv3: An Incremental Improvement


  • YOLO v4(2020)

  2020年4月份预发表,使用了很多最新的通用模块,具有技术的后发优势,通过这些模块的排列组合,调参调出了一种最优模型。当然也有作者创新的模块,例如新的数据增广方式Mosaic和Self-Adversarial Training、改进后的SAM/PAN/Cross mini-Batch BN等。性能上比v3的AP高了10%,FPS高了12%。
  在结构上,把可选用的模块按位置分为了如下图的几个区域;在计算速度上,把模块分成了Bag of freebies(只增加training时间,不增加inference速度,如数据增广、新loss)和Bag of specials(既增加training时间,又增加inference速度,如可增大感受域的模块、attention模块、多尺度特征融合、新的激活函数和后处理方法)。   下面按照Bag of freebies/specials的分类来逐个介绍各个模块,比较熟悉的经典模块会跳过,之前了解较少的模块会单独介绍。

Bag of freebies

数据增广

  – 像素级photometric distortions:调整图片的brightness, contrast, hue, saturation, and noise。
  – 像素级geometric distortions:对图片进行random scaling, cropping, flipping, and rotating.
  – 区域级:random erase、CutOut、hide-and-seek、grid mask、MixUp、CutMix、style transfer GAN(详见texture-shape cue conflict of CNN一文)。

正则化

  主要包括DropOut(在全连接层输出上随机Drop)、DropConnect(在全连接层权重上随机Drop)、maxout(在全连接层中嵌入多个神经元求max)、StochasticDepth(在resnet中随机Drop掉transition保留skip connection)、DropPath(随机Drop部分前向路径)、SpatialDropout(在feature map上随机Drop掉整个Channel的feature)、DropBlock(在feature上随机Drop掉一部分区域)。
  这里针对 DropBlock(NIPS 2018) 做一下记录。
  CNN跟fc不同的地方在于,每一个Channel的feature所提取的特征都具有空间连续性,如果依旧采用传统的Dropout(如下图(b))来逐个像素地drop,则无法对feature起到显著的遮挡效果,也就不具有正则化的效果。因此有了SpatialDropout(CVPR 2015)这种方法,它随机地整体丢弃一个Channel的feature,每一个Channel相当于一个detector,相当于在众多detector之间做Regularization。   DropBlock与SpatialDropout的思想类似,考虑空间信息的整体性,在feature上做块状drop(如上图(c))。 用预设的block_size控制块状的大小,当block_size=1时退化成dropout,当block_size=feature_size时,退化成SpatialDropout。
  文中通过实验发现的一些结论:一、每个Channel使用不同的drop mask比使用相同的drop mask要好;二、开始时不能使用过大的drop_prob,随着epoch的增长缓慢线性增大drop_prob能有更好的效果;三、DropBlock比SpatialDropout和Dropout效果都好;四、block_size取7左右,有较好的效果(仅供参考,不同任务上最优大小不同);五、DropBlock能提升detection和segmentation任务的精度。

原文地址:DropBlock: A regularization method for convolutional networks

数据不平衡

  – two stage:hard negative example mining、online hard example mining。
  – one stage:focal loss。
  – 其他:label smoothing。
  这里针对 label-smoothing regularization(LSR) 做一下详细记录。
  在分类问题中,常用交叉熵作为loss。标签值是互不相同的整数,在计算预测的分布$p(k)$时,用softmax使大的预测值越大,小的预测值越小,迫使它们逼近整数的标签值,这是一种硬分类。硬分类带来的后果就是容易过拟合,类似于没有软间隔的支持向量机。   为了减弱过拟合的风险,增强泛化能力,需要把硬分类转化为软分类。原先的真实分布如下,它非0即1:   为了软化它,使它介于0-1之间,在后增加一个先验项$u(k)$,并分配权重$\epsilon$,形式如下:   这个先验项可定义为均匀分布$u(k)=1/K$,当$\delta=0$时,标签分布$q$不至于为0;当$\delta=1$时,$q$也不至于为1,而是介于0-1之间的值。相当于一方面既要使预测分布$p$靠近标签分布$q$,一方面又要使$p$靠近均匀分布$u$,使得类间分布尽量平衡,不偏向任何一类,减少过拟合的倾向。原文(Inception-v3)中设$\epsilon=0.1$,在ILSVRC 2012上的误差能降低0.6个点。

损失函数

  有常见的MSE loss,以及各种尺度归一化的IoU loss的变体,如GIoU、DIoU、CIoU(详见G/D/C-IoU loss一文)。

Bag of specials

增大感受域

  主要有SPP、ASPP、RFB。
  这里针对 RFB(Receptive Field Block,ECCV 2018) 做一下记录。
  首先,作者炒了一个概念,以仿生学为依据,发现人类视网膜细胞组织中偏心率越大的地方(远离视野中心),感光细胞体积越大,分布越稀疏;换而言之,偏心率越小的地方,感光细胞体积越小越密集。这里的视网膜可视作CNN中的感受域,偏心率对应着偏离感受域中心的程度,感光细胞体积对应着卷积核的大小。   存在即合理,更何况是存在于人的视网膜细胞上。为了模仿出上图这种感受域,作者设计出了如下图的RFB模块。首先一上来是跟Inception一样的多级kernel Conv,Conv的kernel越大,对应着越大体积的感光细胞;然后紧接着是dilation rate不同的atrous Conv(注意kernel大小都为3x3),不同的rate对应着感受域上不同的偏心率;最后三个分支的feature叠加在一起,就形成了中间小且密集、外围大且稀疏的感受域分配。不管它有没有道理,模仿就完事了。   作者也比较了Inception、ASPP、Deformable Conv、RFB这四种多尺度感受域融合模块的结构(如下图)。这其中,跟RFB最接近的就是ASPP了,不同的地方在于ASPP第一层的Conv kernel大小都相同,相当于视野中无论远近如何都是体积大小相同的感光细胞。而Inception则缺少atrous Conv,相当于不同大小的感光细胞都堆到一起了,没有被偏心率所分配开。也就是说,RFB对视网膜的模仿最像。   由此,可构造RFB和RFB-Net。其中,RFB-s模仿的是人类浅层视觉细胞的感受域,细胞核的体积更小,用1xn和nx1代替大的nxn kernel,分支也更多。RFB-Net中,RFB-s也是接在浅层feature后,RFB接在深层feature后。最终的模型效果也还不错,侧重于轻量级且高效提取特征。

原文地址:Receptive Field Block Net for Accurate and Fast Object Detection

attention机制

  代表性的有Squeeze-and-Excitation (SE)、Spatial Attention Module(SAM)、Channel Attention Module(CAM)模块。它们虽然都能以较少的计算代价提升模型性能,但是SE在GPU上会增加10%的inference时间,因此不推荐在GPU上使用,而SAM则对GPU的inference时间无影响。
  这里针对 SAM/CAM(ECCV 2018) 做一下记录。
  原文中对attention的解释是 Attention not only tells where to focus, it also improves the representation of interests,因此能够focusing on important features and suppressing unnecessary ones.   首先是Channel-wise的CAM(如上图),feature map的每一层相当于一个feature detector,因此在channel维度上求得attention,能使得focuses on ‘what’ is meaningful given an input image。作者同时使用了MaxPool和AvgPool,实验结果也显示这样比单独使用任一组分都要好。接下来是Spatial-wise的SAM(如下图),这里的MaxPool和AvgPool都比较特殊,是沿着Channel轴的(不知道Pytorch/Tensorflow有没有官方底层的实现?),这样能使得focuses on ‘where’ is an informative part,并且be effective in highlighting informative regions   由CAM和SAM便组成了Convolutional Block Attention Module(CBAM),互为补充,同时解决whatwhere的问题。在应用中,发现二者串行比并行好,同时CAM-first比SAM-first要好,也就是说先关注what,然后关注where

原文地址:CBAM: Convolutional Block Attention Module

特征复用

  常见的有skip connection、FPN、NAS-FPN、BiFPN、SFAM、ASFF、PAN,核心思想就是把low-level的位置信息和high-level的语义信息融合在一起,提升模型多尺度的性能。
  这里针对 PAN(Path Aggregation Network, CVPR 2018) 做一下记录。其实一目了然,跟FPN的区别就是,FPN是自顶向下的feature融合,PAN则是在FPN的基础上再来了一遍自下向上的融合,让low-level的localization信息和high-level的semantic信息融合更充分。

原文地址:Path Aggregation Network for Instance Segmentation

激活函数

  常见的有ReLU、LReLU、PReLU、ReLU6、ELU、SELU、Swish、hard-Swish、Mish。其中,ReLU6和hard-Swish适用于端上的低比特网络,
  ELUSELU的表达式依次如下,SELU就是在ELU的基础上进行缩放$\lambda$,它们的核心思想都是在ReLU的基础上把输出的平均值向0拉拢,来把输入归一化成零均值单位方差的输出,类似于BN的作用一样实现更快的训练。   Swishhard-Swish的表达式依次如下,hard-Swish就是把Swish中计算量大的$sigmoid$函数替换成硬件友好的$\frac{ReLU6(x+3)}{6}$(且取$\beta=1$)。针对Swish,有可学习的参数$\beta$,当$\beta=0$时退化成线性函数$\frac{x}{2}$;当$\beta=\infty$时退化成ReLU,相当于Swish是线性函数和非线性函数之间的插值,更具灵活性,相对于ReLU有很大的性能提升。   Swish在ReLU的基准上有了很大提升,随后的Mish(表达式如下)又在Swish基准上有了很大提升。尽管作者在文中也坦承it’s difficult to explain the reason why one activation function performs better than another due to many other training factors,但是也总结了几大关键要素。一、无上限,防止因饱和而减缓训练速度;二、有下限,起到正则的作用;三、非单调,使得小的负输入有小的负输出,增加非线性表达能力;四、连续性,光滑的函数形式使得有连续的导数和光滑的梯度,因此易于优化;五、自缩放(Self Gating),这一点是由Swish启发得到,它们的第二项$sigmoid(\beta x)$和$tanh(ln(1+e^x))$代表考虑自身大小的缩放因子,然后作用于自身$x$上。

Batch Normalization

  主要有BN、Cross-GPU BN、Cross-Iteration BN、Filter Response Normalization Layer,详见variants of BN一文。

后处理

  在two-stage anchor-based的方法中,需要对候选框进行挑选,常用的有NMS(详见Paper review - Faster RCNN/YOLO/SSD …一文)、soft NMS、DIoU NMS(详见G/D/C-IoU loss一文)。

模型结构

  backbone选择了CSPNet( Cross Stage Partial Network,CVPR 2020),19年11月发表,一、二作者是YOLO v4的二、三作,自作自引可以理解。   文中的思路首先从DenseNet出发,它具有致密的skip connection,把feature复用发挥到了极致,由此带来的问题是梯度在反向传播的过程中,同一份梯度要同时拷贝回传给前面的多层,在最前面的几层往往承担了较大的计算压力(如上图第一层红色的致密连接)。这样的后果是,层之间的计算压力分配不均,会导致计算资源的不合理分配和浪费,同时也增加了昂贵的内存读取压力。   为了平衡和减轻这种计算压力,面向轻量级运算的CSPNet的思路是,把第一层的feature分成了两部分,第一部分继续参与后续运算,而第二部分则以skip connect的形式直接传送到模块的末端。这样前面层的计算压力就会小很多,使得层之间的计算压力更为平衡,内存读取次数也变少了。这里采用了HarDNet(ICCV 2019)中的评价指标,Convolutional Input/Output (CIO),它跟Dynamic Random-Access Memory (DRAM)之间有近似的正比关系。经过计算,原dense block的CIO是$(c\times m)+((m^2+m)\times d)/2$,而CSPDense block的CIO是$((c\times m)+(m^2+m)\times d)/2$。因为c(channel)远大于m(层数)和d(growth rate),所以作者声称DRAM最多能减少一半。(关于计算资源优化的分析,详见ShuffleNet-v2,内含如何合理分配计算资源、优化内存读取的原则介绍,有空可以整理成一篇文章,TBD)   同理,ResNe(X)t也可做同样的改进,成为CSPResNe(X)t。YOLO v3的Draknet-53做同样的改进,即成了要使用的CSPDarknet53。

原文地址:CSPNET: A NEW BACKBONE THAT CAN ENHANCE LEARNING CAPABILITY OF CNN

  Neck部分选择了SPP加PAN。

部分创新及改进

新数据增广Mosaic

  把四张图按任意区域crop任意大小比例拼接在一起,使得一张图片有更多的物体,并且这些物体的上下文信息可能已经被切掉。除了能引入更多样的场景外,还能在计算BN时按照这四张图的输入计算均值方差,相当于一下子把batch size增加了四倍,提升模型在小batch size时的性能。

Self-Adversarial Training (SAT)

  文中的描述很简短,Self-Adversarial Training (SAT) also represents a new data augmentation technique that operates in 2 forward backward stages. In the 1st stage the neural network alters the original image instead of the network weights. In this way the neural network executes an adversarial attack on itself, altering the original image to create the deception that there is no desired object on the image. In the 2nd stage, the neural network is trained to detect an object on this modified image in the normal way.
  简单的来说,就是狠起来连自己都骗。一张图片做两次forward-backward,第一次backward时产生的梯度不去更新网络参数,而是去更新图片,把它变成一个对抗样本,对抗当前网络参数下的认知;第二次把已改变的对抗图片作为输入,按照正常的forward-backward去更新网络参数,纠正对对抗样本的错误认知,提升模型在hard-case上的辨识能力。

Cross mini-Batch Normalization (CmBN)

  作者对比了BN和CBN的流程(关于CBN详见variants of BN一文),把它们融合在一起创新成了CmBN。首先来看BN,a batch contains four mini-batches,batch里的mini-batches是什么鬼?文中没有具体说明,查了一下相关资料,貌似YOLO在工程实现时采用了“batch中含mini-batch”的做法(文中取batch size为128,mini-batch size为32),由于一个batch的数据太大无法一次性塞入GPU,只好分做$\frac{batch}{mini-batch}$次forward,但每一次mini-batch并不更新参数,而是连续在batch内累计梯度,直到最后一次才更新参数,通过这种工程方式变相增大batch size。所以上图中BN才在最后一个mini-batch更新模型参数和BN漂移参数。
  CBN没有采用“batch里的mini-batch”这种策略,就是正常的训练过程,计算时累计前k步的统计参数做BN,变相增加batch size,推导过程和原理在variants of BN一文有详细的介绍。
  再来看CmBN,就是即采用“batch里的mini-batch”这种策略,也采用CBN的“累计前k步的统计参数”做BN。但不同的是,这里的“前移滑窗k”只在当前batch内,跨越多个mini-batch,而不会像CBN那样跨越多个batch。我们来对比一下CBN和CmBN,假设数据集总共有N个样本,CBN取$batch size=N_{B1}$,那么它实际的跨多步的等效$batch size=N_{B1}\times k_1$;CmBN取$batch size=N_{B2}$,$mini-batch size=\frac{N_{B2}}{k_2}$,那么它实际的跨多mini-batch的等效$batch size=N_{B2}$。二者其实没法比较优劣,YOLO系列本就是工程性很强的paper,东西好不好,效果来证明。

modified SAM

  把SAM中spatial-wise attention换成了point-wise attention,结构如上图。吐槽一句,这样真的有用吗?估计没有什么motivation,只是调参调出来这样发现好用。

modified PAN

  把PAN中的add换成了concate,也是调参调出来的。

最终组合

  经过各种消融实验的比对,作者选用了如上图所示的组合。最终的效果也是很快很好,原文嚣张地在Conclusions中说道,We offer a state-of-the-art detector which is faster (FPS) and more accurate (MS COCO AP50...95 and AP50) than all available alternative detectors   总的来说,YOLO v4虽然没有提出非常创新的模块或者算法,但是却是工程领域调参的集大成者,站在工程角度提出了非常实用的Mosaic、SAT、CmBN这些大胆的trick,同时也站在现有各种算法的肩膀上,实现了SOTA。借用知乎上看到的一句话,第一层是让人耳目一新的创新,例如Faster RCNN、YOLOv1、SSD;第二层是守正出奇的创新,比如从图像金字塔到特征金字塔;第三层是集成改进的创新,堆砌各种其他论文发表的tricks,迁移SOTA方法到其他特定领域。YOLO v4应该属于第三种,在算法的各个层面覆盖得非常广,消融实验也做得非常充分,Github上代码的Readme文档也写得非常详细,劳苦功高,实在是良心之作,也真心感叹现在连各种模块排列组合水论文也变得越来越难了。

原文地址:YOLOv4: Optimal Speed and Accuracy of Object Detection
Github地址:AlexeyAB/darknet


「评论区」: