smooth_BCE

def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441# return positive, negative label smoothing BCE targetsreturn 1.0 - 0.5 * eps, 0.5 * eps

把one-hot label 转换为soft label,一般认为这样更容易work。

BCEBlurWithLogitsLoss

self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss()
这里reduction用none因为在forward里返回的时候取mean。

dx = pred - true  # reduce only missing label effects, false positive
# dx = (pred - true).abs()  # reduce missing label and false label effects
alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4))
loss *= alpha_factor

刚开始看这几行非常confused,查了很久。

https://github.com/ultralytics/yolov5/issues/1030
这个issue里说减少false negative的影响,我觉得应该写错了,是减少false positive的影响。

false negative指gt有框而network没有predict到,这时候的weight应该要比较大才对。

d x ∈ [ − 1 , 1 ] dx\in [-1,1] dx∈[−1,1],当 d x = 1 dx=1 dx=1 ,即 p r e d = 1 , t r u e = 0 pred=1,true=0 pred=1,true=0 时,alpha_factor=0,这应该是false positive的情况。

直白的说,network觉得这里有一个obj,但是gt说没有,这种情况不应该过多的惩罚。

如果采用绝对值的话,会减轻pred和gt差异过大造成的影响。

Focal Loss

class FocalLoss(nn.Module):# Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)def __init__(self, loss_fcn, gamma=1.5, alpha=0.25):super(FocalLoss, self).__init__()self.loss_fcn = loss_fcn  # must be nn.BCEWithLogitsLoss()self.gamma = gammaself.alpha = alphaself.reduction = loss_fcn.reductionself.loss_fcn.reduction = 'none'  # required to apply FL to each elementdef forward(self, pred, true):loss = self.loss_fcn(pred, true)# TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.pypred_prob = torch.sigmoid(pred)  # prob from logitsp_t = true * pred_prob + (1 - true) * (1 - pred_prob)alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)modulating_factor = (1.0 - p_t) ** self.gammaloss *= alpha_factor * modulating_factorif self.reduction == 'mean':return loss.mean()elif self.reduction == 'sum':return loss.sum()else:  # 'none'return loss

假设gt是1,pred_prob如果很小,那么就是hard,这样算出来的p_t也会小,最后modulating_factor大。

对alpha_factor也是类似的。alpha_factor对应于foreground,一般设置为0.25。

QFocalLoss

class QFocalLoss(nn.Module):# Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)def __init__(self, loss_fcn, gamma=1.5, alpha=0.25):super(QFocalLoss, self).__init__()self.loss_fcn = loss_fcn  # must be nn.BCEWithLogitsLoss()self.gamma = gammaself.alpha = alphaself.reduction = loss_fcn.reductionself.loss_fcn.reduction = 'none'  # required to apply FL to each elementdef forward(self, pred, true):loss = self.loss_fcn(pred, true)pred_prob = torch.sigmoid(pred)  # prob from logitsalpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)modulating_factor = torch.abs(true - pred_prob) ** self.gammaloss *= alpha_factor * modulating_factorif self.reduction == 'mean':return loss.mean()elif self.reduction == 'sum':return loss.sum()else:  # 'none'return loss

这里modulating_factor的算法和QFL论文写的一致。

原本FL用class label,也就是one-hot discrete label来supervise;而QFL将其换成了IoU continuous label。

ComputeLoss

我们先明确一下p和targets的shape
p,也就是prediction,[num_dec_layer, batch_size, num_anchor, height, width, 85],这里85是80个class和4个offset以及1个confidence。
targets [nt, 6]

init

BCEcls, BCEobj是两个criteria,在scratch的hyp中g=0所以没有用focal loss,是普通的BCEloss

cp 和 cn 是soft label的probability,比如0.95 0.05。

balance控制obj loss的加权系数,autobalance决定加权系数也就是balance是否自动更新,autobalance一般是False。

self.balance = {3: [4.0, 1.0, 0.4]},有三个layer的输出,第一个layer的weight是4,第二个1,以此类推。如果有5个layer的输出才用右边那个weight数组。

gr 是iou ratio。

build_targets

targets就是这个batch里所有的labels,targets(img_idx, cls_idx, x, y, w, h),shape为[nt, 6]。可参考utils/datasets.py line 522, 599。
随便打印几行targets也可以验证我们的分析。

...,
[2.00000e+00, 5.40000e+01, 4.65345e-01, 8.84894e-01, 1.62460e-01, 2.30211e-01],
[3.00000e+00, 2.20000e+01, 3.53780e-01, 5.08301e-01, 6.05865e-01, 5.20621e-01],
...,

x, y, w, h是归一化后的结果。

gain = torch.ones(7, device=targets.device)  # normalized to gridspace gain, [7,]
ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt)  # same as .repeat_interleave(nt), [na,nt]
targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2)  # append anchor indices, [na, nt, 7]

先复制了三份一样的targets,在最后面加了一维表明anchor idx,本来是6现在变成7。

...,
[3.00000e+00, 4.40000e+01, 8.23209e-01,  ..., 2.10690e-02, 2.45219e-02, 1.00000e+00]],
[[0.00000e+00, 4.50000e+01, 4.14857e-01,  ..., 8.29713e-01, 5.83730e-01, 2.00000e+00],
...,

gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain t = targets * gain这里是把 grid size 拿出来乘,恢复到特征图的维度。

在 match 里面比较简单,容易看懂,就是 anchor 和 target 不能差的太离谱,误差小于阈值就 match。

下一步在扩展 targets,个人认为是 positive examples 太少了,所以根据 center 在 cell 中的相对位置,添加相邻的两个 cell 作为 targets。

举个例子,如果 center 在 cell 的左上角,那么 cell 本身,和 cell 的左边一个位置,还有 cell 的上边一个位置,这三个 cell 都作为 targets。

我个人觉得这里的写法是非常巧妙的,取了 grid xy 和 inverse(类似于 flip)。

(gxy % 1. < g),这里的 g 是 0.5,如果仅考虑这个条件,好像可以直接判断是否选取左边 cell 和上边 cell。

但是要考虑到边界情况,如果当前已经处于最上方,已经没有上边 cell 可以选择了,这就是(gxy > 1.)起到的作用,判断 edge case。

如果本来大于 0.5,那么 inverse 后就小于 0.5 了,所以可以使用相同的逻辑选择右边 cell 和下边 cell ,类似地推理到 edge case。

最后一点要提的是使用 clamp_ 确保返回的 grid indices 不是非法值,旧版本 code 没用这个检查,不过好像也没什么差。

call

lcls, lbox, lobj 这三个用来存放loss,默认使用pytorch提供的BCE loss。

pxy = ps[:, :2].sigmoid() * 2. - 0.5 在learn的时候不需要加cx cy。

bbox回归的公式可以参考model/yolo.py line56, 57。

Objectness 这里 gr 设置为 1.0,也就意味着直接拿 iou 作为 confidence。

至于为什么返回 loss 的时候为什么要乘 bs,还不是很清楚,第二个返回值就是为了打印信息用的。

tips

scale

在train的时候,target是在feature map的scale。

在inference的时候,直接乘img map scale的anchor size就可以了,也就是配置文件里的anchor。

yolov5 代码解读 损失函数 loss.py相关推荐

  1. YOLOV5代码理解——损失函数的计算

    YOLOV5代码理解--损失函数的计算 摘要: 神经网络的训练的主要流程包括图像输入神经网络, 得到模型的输出结果,计算模型的输出与真实值的损失, 计算损失值的梯度,最后用梯度下降算法更新模型参数.损 ...

  2. Faceboxes pytorch代码解读(一) box_utils.py(上篇)

    Faceboxes pytorch代码解读(一) box_utils.py(上篇) 有幸读到Shifeng Zhang老师团队的人脸检测论文,感觉对自己的人脸学习论文十分有帮助.通过看别人的paper ...

  3. yolov5 代码解读 --common.py

    先从common.py学起,接下来的近期时间将会对yolov5的代码进行解析,以及对yolov5的网络结构进行解析. 在common.py文件中主要是封装了不同的通用模块 1:头文件 这是common ...

  4. Yolov5代码详解——detect.py

    首先执行扩展包的导入: import argparse import os import platform import sys from pathlib import Path ​ import t ...

  5. YoloV5代码详细解读

    本文重点描述开源YoloV5代码实现的细节,不会对YoloV5的整体思路进行介绍,整体思路可以参考江大白的博客 江大白:深入浅出Yolo系列之Yolov3&Yolov4&Yolov5& ...

  6. 【YOLOV5-5.x 源码解读】common.py

    目录 前言 0.导入需要的包和基本配置 1.基本组件 1.1.autopad 1.2.Conv 1.3.Focus 1.4.Bottleneck 1.5.BottleneckCSP 1.6.C3 1. ...

  7. 图像分割套件PaddleSeg全面解析(一)train.py代码解读

    首先祝贺百度团队百度斩获NeurIPS2020挑战赛冠军,https://www.jiqizhixin.com/articles/2020-12-09-2. 在此次比赛中使用的是基于飞桨深度学习框架开 ...

  8. 说话人识别损失函数的PyTorch实现与代码解读

    概述 说话人识别中的损失函数分为基于多类别分类的损失函数,和端到端的损失函数(也叫基于度量学习的损失函数),关于这些损失函数的理论部分,可参考说话人识别中的损失函数 本文主要关注这些损失函数的实现,此 ...

  9. 【代码解读】超详细,YOLOV5之build_targets函数解读。

    文章目录 build_targets作用 注意 可视化结果 过程 详细代码解读 准备 第一遍筛选 扩增正样本 Reference build_targets作用 build_targets函数用于网络 ...

最新文章

  1. Paper4:Voxel-Based Extraction and Classification of 3-D Pole-Like Object From Mobile LIDAR Point Clo
  2. Mass对象类型介绍
  3. 贪心 - 划分字母区间
  4. 验证二叉搜索树Python解法
  5. Oralce定时任务实际应用
  6. Centos7 操作系统 mysql5.7 配置远程登陆操作
  7. 监控三剑客<cacti、nagios、zabbix>
  8. Kubernetes详解(二十六)——金丝雀发布
  9. Mac 下 CocoaPods软件⁩汉化
  10. Java实现网页滑动验证与短信验证码案例精析
  11. 在大米云主机中采用CentOS 6.5 部署Redmine 3.3
  12. python试卷河南理工大学官网_河南理工大学试卷模板
  13. 阿里云服务器安装宝塔流程
  14. 华硕固件无线打印机服务器设置,华硕路由器远程打印机LPD设置-Windows.pdf
  15. 派工单系统 源码_「VIP报修云」报修工单进度通知方法
  16. theHarvester使用
  17. 三国志战略版:Daniel_马腾分析
  18. python:性能优化(一)
  19. php删除bom,php bom如何去掉
  20. U盘版的DOS启动盘制作

热门文章

  1. 发撒富商大贾是的鬼地方和
  2. 1000行代码写小游戏(二)
  3. SQL练习 demo1_select_查询语句
  4. linux shell 字符串替换字符,关于bash:在shell脚本中替换另一个字符串的一个子字符串...
  5. 【C语言】MAC地址格式化转换
  6. workerman 聊天demo
  7. js ajax获得对象怎么放到td上,jquery通过AJAX从后台获取信息并显示在表格上,并支持行选中...
  8. springboot整合rocketmq报错
  9. BLENDER参数调节皮革纹理
  10. 思科Wi-Fi5 AP传统模式转换为ME