YOLO系列算法(v3v4)损失函数详解

本文详细解析YOLOv3的目标检测算法损失函数,通过百度飞桨PaddleDetection实现为例,介绍YOLOv3的输出张量、感受野、目标分配策略以及损失计算过程,包括xywh损失、iou损失、置信度损失和分类损失。同时讨论了正负样本的选择和置信度损失中‘忽略样本’的作用。最后分享了YOLOv4及其他相关项目的GitHub链接。
摘要由CSDN通过智能技术生成

YOLO算法是One-Stage目标检测算法的开山之作,一面世就注定不平凡。而在监督学习中,损失函数指导着模型的学习方向,占据着非常重要的地位。今天就由笔者来给大家讲解YOLO系列算法的损失函数。由于原版YOLO算法使用C语言编写,可能晦涩难懂,所以这里笔者选择了百度飞桨PaddleDetection(版本0.3.0)中复现的YOLOv3为例进行讲解,项目地址 https://github.com/PaddlePaddle/PaddleDetection

相信你看完这篇文章,再看YOLOv4的代码或许就突然豁然开朗了,因为损失函数部分是差不多的。好了废话不多说,下面进入正题。本文基于读者对YOLOv3算法有一定了解。

YOLOv3算法,如果你看过关于它的博客或一些第三方实现的话会知道,它有3个输出张量,这三个输出张量的形状是(bz,3*(4+1+80), 13, 13),(bz,3*(4+1+80), 26, 26),(bz,3*(4+1+80), 52, 52)。其中的bz代表批大小,3代表一个格子会出3个预测框,而4+1+80代表一个预测框会携带有85位信息,前4位代表预测框的中心位置xy以及大小wh,第5位代表置信度,表示该预测框是前景的概率,最后的80位代表如果是前景,那么预测框是80种物体的概率(COCO数据集中类别数是80)。然后后面的13、26、52就是代表一行(一列)的格子数了。第一个张量,形状是(bz,3*(4+1+80), 13, 13),代表它输出了13x13个网格,预测框数目是bz*3*13*13;第二个张量,形状是(bz,3*(4+1+80), 26, 26),代表它输出了26x26个网格,预测框数目是bz*3*26*26;第三个张量,形状是(bz,3*(4+1+80), 52, 52),代表它输出了52x52个网格,预测框数目是bz*3*52*52。

 

这三个张量就构成了YOLOv3的输出。这里也有必要再讲解一个知识点——感受野。感受野即CNN能看到的视野大小。比如,一个3x3的卷积层,卷积核个数=1,步长stride=1,padding=1,一个形状为(N, C, H, W)的张量tensor1,经过这个卷积层之后,变成了形状为(N, 1, H, W)的张量tensor2。那么新张量tensor2一个像素里包含了tensor1多少个像素的信息呢?3x3=9个。张量tensor2的一个像素“看到了”原始特征图张量tensor1相同位置像素9宫格像素的内容,也就是说张量tensor2感受野是3x3大小了。假如我把卷积层换成了1x1卷积层呢?那么只能“看到”原始特征图张量tensor1相同位置像素的内容,也就是说张量tensor2感受野是1x1大小。我再变点花样,tensor1经过了2个卷积层,第一个卷积层是3x3大小,卷积核个数=1,步长stride=1,padding=1,第二个卷积层是3x3大小,卷积核个数=1,步长stride=1,padding=1,tensor1经过了这2个卷积层变成了张量tensor2,敢问张量tensor2感受野大小?5x5,张量tensor2的一个像素“看到了”原始特征图张量tensor1相同位置像素附近5x5像素的内容。我再变点花样,tensor1经过了2个卷积层,第一个卷积层是3x3大小,卷积核个数=1,步长stride=2,padding=1,第二个卷积层是3x3大小,卷积核个数=1,步长stride=1,padding=1,tensor1经过了这2个卷积层变成了张量tensor2,敢问张量tensor2感受野大小?7x7,张量tensor2的一个像素“看到了”原始特征图张量tensor1相同位置像素附近7x7像素的内容。我们可以看到,叠加卷积层可以扩大感受野大小,卷积步长也会影响感受野大小。

 

回到正题,我们的这3个输出张量中,13x13的张量有大感受野,它会被分配到3个最大尺度的先验框,26x26的张量有中感受野,它会被分配到3个中等尺度的先验框,52x52的张量有小感受野,它会被分配到3个最小尺度的先验框。这样,这一层每个格子都会被分到3个先验框,分别给了这个格子的3个预测框使用。毕竟是监督学习,监督信息也必须要有,我们的label张量也是差不多同样的形状。在PaddleDetection中,训练时会先预处理图片,比如读图片、进行数据增强、坐标归一化、随机尺度、随机插值等,数据预处理最后阶段就是Gt2YoloTarget,Gt2YoloTarget()类里就准备好了我们的label张量,我们看看它的神秘面纱:

...
grid_h = int(h / downsample_ratio)
grid_w = int(w / downsample_ratio)
target = np.zeros((len(mask), 6 + self.num_classes, grid_h, grid_w), dtype=np.float32)
for b in range(gt_bbox.shape[0]):
    gx, gy, gw, gh = gt_bbox[b, :]
    cls = gt_class[b]
...

即target,形状是(3,(6+80), grid_h, grid_w),没有批大小那一维是因为是在遍历每一张图片,后面会拼接这一批所有图片的target(不同的输出层分开拼接)。3代表每个格子有3个预测框的注解,(6+80)就有点迷,小编,你刚才不是说每个预测框会输出85位信息的吗?没错,但是我们的label可以带多一些信息,后面你也会看到,我们带多了另外的张量来在训练过程中确定负样本。我们继续看:

...
# x, y, w, h, scale
target[best_n, 0, gj, gi] = gx * grid_w - gi
target[best_n, 1, gj, gi] = gy * grid_h - gj
target[best_n, 2, gj, gi] = np.log(gw * w / self.anchors[best_idx][0])
target[best_n, 3, gj, gi] = np.log(gh * h / self.anchors[best_idx][1])
target[best_n, 4, gj, gi] = 2.0 - gw * gh

# objectness record gt_score
target[best_n, 5, gj, gi] = score
# classification
target[best_n, 6 + cls, gj, gi] = 1.
...

找到了!这是某个预测框被选定为正样本时需要做的事。我们看到,0、1位用来监督xy,2、3位用来监督wh,第4位填了一个权重,即2 - gw*gh,由于预处理阶段gw、gh进行了归一化,所以这个权重表示的是“2.0 - gt的面积/输入图片大小的面积”,亦即“2.0 - gt面积占图片面积的比重”。第4位表明,若gt面积越小,权重越接近2,若gt面积越大,权重越接近1。这个权重叫做tscale,在后面的xywh损失、iou损失计算那里都会乘上,注意这些损失都是和预测框的位置有关。而分类损失和预测框位置无关,不用乘tscale。乘以tscale表明,若gt越小,它应该越受到重视,由此改善小目标检测。然后第5位是置信度,是填的score,如果你没用mixup增强,会是1,用了mixup增强,它会是0~1

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值