PP-YOLO论文中小tricks的个人理解


论文地址: https://arxiv.org/abs/2007.12099
代码: https://github.com/PaddlePaddle/PaddleDetection

摘要

一句话,在yolov3上运用已被证实有效的tricks的堆叠,在保证模型速度的情况下达到了较高的检测精度。
个人理解:PPYOLO就是在各种已存在的tricks进行改进做SOTA,相比于YOLOv4,PPYOLO没有在骨干网络和数据增强上做变换,拓展性还是较强的。可以方便我们做炼丹(滑稽脸)

介绍

在这里插入图片描述
见图,PPYOLO在使用ResNet骨干网络和仅使用MixUp数据增强的情况下,在一系列的tricks的加持下达到覆盖YOLOv4的性能。

方法

网络结构

在这里插入图片描述
文章讲选择ResNet作为Backbone的原因是学者们对于ResNet的研究深入,其变种网络在一些场景中优化也很好,因此换掉了YOLOv3的DarkNet,采用ResNet。由于直接替换ResNet不可避免的造成精度下降,因此论文中提到使用了可变形卷积,因为可变形卷积带来的参数量和FLOPs较大,因此只在最末尾代替了3x3的卷积。
Neck使用了特征金字塔结构,每层的输出的特征图长宽大小为输入的1/2。
Head基本上和YOLOv3的一致,但在本文后面会提到对Head的一些改进。

Trick

终于到本文最重要的环节了,话不多说,冲冲冲。

Trick1、大的batch_size

大尺寸的batch_size可以提高训练的稳定性和得到更优秀的结果,论文中将batch_size从64提到196,卡多就是硬气。

Trick2、EMA

在这里插入图片描述

这个就是公式了,先介绍一下EMA的作用:在训练模型的时候,使用滑动平均(EMA)来更新参数,可以使得参数更新更加稳定,从而使得训练出来的模型对测试数据的拟合也更加健壮。λ的取值一般是0.9999,这种接近于1的数。

在我的理解看来改公式是对1-λ的倒数的个数的W做平均,可能有人会问,为什么不直接做W的平均。直接对W做平均需要记录N个W的数值,这是非常消耗内存的。这个公式就可以满足在内存受限制的条件下做平均。

λ越接近于1所记忆的数据就越多,就越平均,例如有五十个数据,λ = 0.9,即EMA对10个数据做平均。λ越大,当前数据所占比重就越小,历史数据所占比重就越大。

那为什么用EMA可以使参数稳定数据拟合更有效呢?

我们可以这样想,如果对数据记录的更多,单个数据的大小对权值产生的影响会减小很多
,使模型不容易出现拟合某一数据的情况,而是根据数据集的分布而产生拟合的。

Trick3、DropBlock

这个技巧是将特征图上随意抛弃连续的几块区域,即将这几块区域置零。论文中只在Head使用了,没有在Backbone使用,原因是作者发现在骨干网络使用会让精度下降。不过不知道论文的图是不是错了原因,论文中说在图中标注三角形的为使用了DropBlock,图中标注三角形的为Neck,但文中又提到这个模块是放在Head上的,不知道有没有好兄弟帮我解答一下这个疑问。
DropBlock实现的公式:
在这里插入图片描述
这里的γ为drop的概率,即为伯努利函数的概率。
block_size为抛弃的区域的面积
feat_size为特征图大小

实现的步骤为
1、输入为feature map,block_size,γ
2、若不为训练模式,直接返回feature map(即在测试过程中不使用dropblock)
3、按伯努利分布采样Mask
4、对于每个0 的位置Mij,创建以Mij为中心,长宽为block_size的空间正方形Mask,并将正方形Mask所覆盖的位置全部置零。该实现过程是max pooling操作(stride=1,kernel_size=block_size)
5、新的feature = featureMask
6、特征归一化:新的feature = 新的feature
count(Mask)/sum(Mask)

配合代码理解更佳

#!/usr/bin/env python
# -*- coding:utf8 -*-
import torch
import torch.nn.functional as F
from torch import nn
 
 
class Drop(nn.Module):
    def __init__(self, drop_prob=0.1, block_size=7):
        super(Drop, self).__init__()
 
        self.drop_prob = drop_prob
        self.block_size = block_size
 
    def forward(self, x):
        if self.drop_prob == 0:
            return x
        # 设置gamma,比gamma小的设置为1,大于gamma的为0,对应第五步
        # 这样计算可以得到丢弃的比率的随机点个数
        gamma = self.drop_prob / (self.block_size**2)
        mask = (torch.rand(x.shape[0], *x.shape[2:]) < gamma).float()
 
        mask = mask.to(x.device)
 
        # compute block mask
        block_mask = self._compute_block_mask(mask)
        # apply block mask,为算法图的第六步
        out = x * block_mask[:, None, :, :]
        # Normalize the features,对应第七步
        out = out * block_mask.numel() / block_mask.sum()
        return out
 
    def _compute_block_mask(self, mask):
        # 取最大值,这样就能够取出一个block的块大小的1作为drop,当然需要翻转大小,使得1为0,0为1
        block_mask = F.max_pool2d(input=mask[:, None, :, :],
                                  kernel_size=(self.block_size,
                                               self.block_size),
                                  stride=(1, 1),
                                  padding=self.block_size // 2)
        if self.block_size % 2 == 0:
            # 如果block大小是2的话,会边界会多出1,要去掉才能输出与原图一样大小.
            block_mask = block_mask[:, :, :-1, :-1]
        block_mask = 1 - block_mask.squeeze(1)
        return block_mask

Trick4、IOU Loss

YOLOv3中对于定位损失采用的是L1损失,这个方法并不适用于目标检测,如下图,在L1损失相同的情况下,IOU不同,且预测框和真实框的相交方式和面积也各不相同。同时,L1损失的对四个坐标点独立的计算损失,没有考虑到他们作为一个锚框的整体。其次L1损失并不具备尺度不变性。因此统一评价指标和损失函数对于训练定位框回归有较好的作用。相对于YOLOv4直接替换掉L1损失,PPYOLO增加一个分支计算IoU损失。
在这里插入图片描述
Iou损失的公式为IoU loss = -ln(Intersection/Union),即负的两框相交的面积除以相并的面积取对数

Trick5、IOU Aware

在YOLOv3中,通常将分类与个目标得分作为最终检测的置信度,这种方法没有考虑到定位精度对最终检测的置信度的影响,例如,在NMS时,只考虑到了目标得分,并对box进行排序,这忽略了高IoU但低目标得分的box,另外,在计算AP时也是同上面一样忽略了IoU的作用。

因此IoU Aware提出了增加一个分支来衡量定位精度对最终检测置信度的影响,虽然带来了一部分计算量和参数,但这些计算量和参数很小,可以忽略不计。

具体公式如下:
在这里插入图片描述
添加了一个IoU预测head,用于预测anchor的IoU,即公式4.
在这里插入图片描述
在推理时,每个anchor的分数计算方式如公式5,参数α用于控制分类和IoU的权重。可以看出,最终分数能很好地关联分类置信度和定位准确率

Trick6、Grid Sensitive

YOLOv3中的坐标与网络输出的结果关系如下:
在这里插入图片描述
其中σ为sigmoid参数,由于sigmiod函数两端趋于平滑。若所预测的box的坐标点落在单元格边框上,则需要将Px,Py预测的足够大才能拟合目标点,不平滑的Px,Py不利于网络的训练及测试,需要有个缩放因子将其扩大,缓解这种情况。
因此PPYOLO提出了如下公式来克服边界敏感情况:
在这里插入图片描述

Trick7、Matrix NMS

针对传统的NMS算法耗时的缺点,论文分析了由于其串行的机制占主要原因。因此在PPYOLO中NMS替换为Matrix NMS。Matrix NMS将mask IoU并行化是它最大的一个贡献。然后同样采取了得分惩罚机制来抑制冗余mask。

Trick8、CoordConv

让网络可以学习到平移不变性,主要手法是增加了两个关于坐标的通道,让训练出来的网络对于位置更加敏感。PPYOLO考虑到其带来的参数和计算量,仅在FPN的1
x1卷积中和Head的第一个卷积中使用了该结构。

在这里插入图片描述

Trick9、SPP

SPP是我们的好朋友了,通过SPP层可以扩大感受野,得到更丰富的语义信息。虽然SPP层本身不带来计算量,但是由SPP产生的多余的通道会使计算量增加。PPYOLO引入{1, 5, 9, 13}这几种大小的最大池化。

Trick10、Better Pretrain Model

使用更好的预训练模型可以让模型的效果更棒,PPYOLO使用了蒸馏的ResNet50-vd作为与训练模型。

结语

本人也是刚入门,可能关于以上的小tricks有理解不对的地方,希望大佬可以指正,欢迎交流和评论。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值