动手学CV-目标检测入门教程5:损失函数

3.5 损失函数

本文来自开源组织 DataWhale 🐳 CV小组创作的目标检测入门教程。

对应开源项目 《动手学CV-Pytorch》 的第3章的内容,教程中涉及的代码也可以在项目中找到,后续会持续更新更多的优质内容,欢迎⭐️。

如果使用我们教程的内容或图片,请在文章醒目位置注明我们的github主页链接:https://github.com/datawhalechina/dive-into-cv-pytorch

3.5.1 Matching strategy (匹配策略):

我们分配了许多prior bboxes,我们要想让其预测类别和目标框信息,我们先要知道每个prior bbox和哪个目标对应,从而才能判断预测的是否准确,从而将训练进行下去。

不同方法 ground truth boxes 与 prior bboxes 的匹配策略大致都是类似的,但是细节会有所不同。这里我们采用SSD中的匹配策略,具体如下:

第一个原则: 从ground truth box出发,寻找与每一个ground truth box有最大的jaccard overlap的prior bbox,这样就能保证每一个groundtruth box一定与一个prior bbox对应起来(jaccard overlap就是IOU,如图3-26所示,前面介绍过)。 反之,若一个prior bbox没有与任何ground truth进行匹配,那么该prior bbox只能与背景匹配,就是负样本。

在这里插入图片描述

图3-26 IOU

一个图片中ground truth是非常少的,而prior bbox却很多,如果仅按第一个原则匹配,很多prior bbox会是负样本,正负样本极其不平衡,所以需要第二个原则。

第二个原则: 从prior bbox出发,对剩余的还没有配对的prior bbox与任意一个ground truth box尝试配对,只要两者之间的jaccard overlap大于阈值(一般是0.5),那么该prior bbox也与这个ground truth进行匹配。这意味着某个ground truth可能与多个Prior box匹配,这是可以的。但是反过来却不可以,因为一个prior bbox只能匹配一个ground truth,如果多个ground truth与某个prior bbox的 IOU 大于阈值,那么prior bbox只与IOU最大的那个ground truth进行匹配。

注意:第二个原则一定在第一个原则之后进行,仔细考虑一下这种情况,如果某个ground truth所对应最大IOU的prior bbox小于阈值,并且所匹配的prior bbox却与另外一个ground truth的IOU大于阈值,那么该prior bbox应该匹配谁,答案应该是前者,首先要确保每个ground truth一定有一个prior bbox与之匹配。

用一个示例来说明上述的匹配原则:

在这里插入图片描述

图3-27

图像中有7个红色的框代表先验框,黄色的是ground truths,在这幅图像中有三个真实的目标。按照前面列出的步骤将生成以下匹配项:

在这里插入图片描述

图3-28

3.5.2 损失函数

下面来介绍如何设计损失函数。

将总体的目标损失函数定义为 定位损失(loc)和置信度损失(conf)的加权和:

L(x,c,l,g)=1N(Lconf(x,c)+αLloc(x,l,g))(1)L(x,c,l,g) = \frac{1}{N}(L_{conf}(x,c)+\alpha L_{loc} (x,l,g)) (1) L(x,c,l,g)=N1(Lconf(x,c)+αLloc(x,l,g))(1)

其中N是匹配到GT(Ground Truth)的prior bbox数量,如果N=0,则将损失设为0;而 α 参数用于调整confidence loss和location loss之间的比例,默认 α=1

confidence loss是在多类别置信度c上的softmax loss,公式如下:

Lconf(x,c)=−∑i∈PosNxijplog(c^ip)−∑i∈Neglog(c^i0)Wherec^ip=exp(cip)∑pexp(cip)(2)L_{conf}(x,c) = -\sum_{i \in Pos}^N x^{p}_{ij} log(\hat{c}^{p}_{i}) - \sum_{i \in Neg} log(\hat{c}^{0}_{i}) Where \hat{c}^{p}_{i} = \frac{exp(c^{p}_{i})}{\sum_p exp(c^{p}_{i})} (2) Lconf(x,c)=iPosNxijplog(c^ip)iNeglog(c^i0)Wherec^ip=pexp(cip)exp(cip)(2)

其中i指代搜索框序号,j指代真实框序号,p指代类别序号,p=0表示背景。其中xijp={1,0}x^{p}_{ij}=\left\{1,0\right\}xijp={1,0} 中取1表示第i个prior bbox匹配到第 j 个GT box,而这个GT box的类别为 p 。CipC^{p}_{i}Cip 表示第i个搜索框对应类别p的预测概率。此处有一点需要关注,公式前半部分是正样本(Pos)的损失,即分类为某个类别的损失(不包括背景),后半部分是负样本(Neg)的损失,也就是类别为背景的损失。

而location loss(位置回归)是典型的smooth L1 loss

Lloc(x,l,g)=∑i∈Posm∈{cx,cy,w,h}N∑xijksmoothL1(lim−g^jm)(3)L_{loc}(x,l,g) = \sum_{i \in Pos m \in \left\{c_x,c_y,w,h\right\}}^N \sum x^{k}_{ij} smooth_{L1}(l^{m}_{i}-\hat{g}^{m}_{j}) (3) Lloc(x,l,g)=iPosm{cx,cy,w,h}NxijksmoothL1(limg^jm)(3)

g^jcx=(gjcx−dicx)/diw\hat{g}^{c_x}_{j}=(g^{c_x}_{j}-d^{c_x}_{i})/d^{w}_{i} g^jcx=(gjcxdicx)/diw

g^jcy=(gjcy−dicy)/dih\hat{g}^{c_y}_{j}=(g^{c_y}_{j}-d^{c_y}_{i})/d^{h}_{i} g^jcy=(gjcydicy)/dih

g^jw=log(gjwdiw)\hat{g}^{w}_{j}=log(\frac{g^{w}_{j}}{d^{w}_{i}}) g^jw=log(diwgjw)

g^jh=log(gjhdih)\hat{g}^{h}_{j}=log(\frac{g^{h}_{j}}{d^{h}_{i}}) g^jh=log(dihgjh)

其中,l为预测框,g为ground truth。(cx,xy)为补偿(regress to offsets)后的默认框d的中心,(w,h)为默认框的宽和高。更详细的解释看-看下图:

在这里插入图片描述

3.5.3 Hard negative mining:

值得注意的是,一般情况下negative prior bboxes数量 >> positive prior bboxes数量,直接训练会导致网络过于重视负样本,预测效果很差。为了保证正负样本尽量平衡,我们这里使用SSD使用的在线难例挖掘策略(hard negative mining),即依据confidience loss对属于负样本的prior bbox进行排序,只挑选其中confidience loss高的bbox进行训练,将正负样本的比例控制在positive:negative=1:3。其核心作用就是只选择负样本中容易被分错类的困难负样本来进行网络训练,来保证正负样本的平衡和训练的有效性。

举个例子:假设在这 441 个 prior bbox 里,经过匹配后得到正样本先验框P个,负样本先验框 441−P 个。将负样本prior bbox按照prediction loss从大到小顺序排列后选择最高的M个prior bbox。这个M需要根据我们设定的正负样本的比例确定,比如我们约定正负样本比例为1:3时。我们就取M=3P,这M个loss最大的负样本难例将会被作为真正参与计算loss的prior bboxes,其余的负样本将不会参与分类损失的loss计算。

3.5.4 小结

本小节介绍的内容围绕如何进行训练展开,主要是3块:

  • 先验框与GT框的匹配策略
  • 损失函数计算
  • 难例挖掘

这3部分是需要结合在一起理解,我们再整个梳理下计算loss的步骤

1)先验框与GT框的匹配

按照我们介绍的方案,为每个先验框都分配好类别,确定是正样本还是负样本。

2)计算loss

按照我们定义的损失函数计算 分类loss 和 目标框回归loss

负样本不计算目标框的回归loss

3)难例挖掘

上面计算的loss中分类loss的部分还不是最终的loss

因为负样本先验框过多,我们要按一定的预设比例,一般是1:3,将loss最高的那部分负样本先验框拿出来,其余的负样本忽略,重新计算分类loss

完整loss计算过程的代码见model.py中的 MultiBoxLoss 类。

共勉:这一小节是整个章节中最难理解,也是代码最难啃的部分,坚持就是胜利~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Modbus协议栈开发笔记之四:Modbus TCP Client开发

这一次我们封装Modbus TCP Client应用。同样的我们也不是做具体的应用,而是实现TCP客户端的基本功能。我们将TCP客户端的功能封装为函数,以便在开发具体应用时调用。 对于TCP客户端我们主要实现的功能有两个:其一是生成访问TCP服务器的命令&…

动手学CV-目标检测入门教程6:训练与测试

3.6、训练与测试 本文来自开源组织 DataWhale 🐳 CV小组创作的目标检测入门教程。 对应开源项目 《动手学CV-Pytorch》 的第3章的内容,教程中涉及的代码也可以在项目中找到,后续会持续更新更多的优质内容,欢迎⭐️。 如果使用我…

PC软件开发技术之一:在WinCC中通过VBS操作SQL Server2005

在项目中需要在一定条件满足时,保存一些数据到数据库中,并可根据条件查询。考虑到WinCC6.2以后采用的就是SQL Server2005数据库,所以直接利用该数据库即可,通过SQL Server Management Studio(SSMS)可以创建…

K 近邻算法(KNN)与KD 树实现

KD树节点 /// <summary>/// &#xff2b;&#xff24;树节点/// /2016/4/1安晟添加/// </summary>[Serializable]public class KDTreeNode{/// <summary>/// 获取或设置节点的空间坐标/// </summary>public double[] Position { get; set; }/// <…

PC软件开发技术之二:用C#开发基于自动化接口的OPC客户端

OPC全称是Object Linking and Embedding&#xff08;OLE&#xff09; for Process Control&#xff0c;它的出现为基于Windows的应用程序和现场过程控制应用建立了桥梁。OPC作为一整套接口、属性和方法的协议标准集&#xff0c;与具体的开发语言没有关系。 1、OPC客户端接口方…

标记符控制的分水岭算法原理及matlab实现

-------------------------------------------------------------------------------------------------------------------- 附录A 教程【3】给出的matlab源码&#xff0c;附详细注释 function [ ] MarkerControlled_Watershed_tutorial( ) %标记符控制的分水岭算法教程 …

PC软件开发技术之三:C#操作SQLite数据库

我们在开发应用是经常会需要用到一些数据的存储&#xff0c;存储的方式有多种&#xff0c;使用数据库是一种比较受大家欢迎的方式。但是对于一些小型的应用&#xff0c;如一些移动APP&#xff0c;通常的数据库过于庞大&#xff0c;而轻便的SQLite则能解决这一问题。不但操作方便…

自动搜索数据增强方法分享——fast-autoaugment

前言 简短的介绍下分享fast-autoaugment的原因 毫无疑问数据增强对于训练CNN非常有效&#xff0c;大家也在不断发明新的数据增强方法 拿到一份数据集&#xff0c;我们凭借之前的经验组合不同的增强方法形成一个数据增强策略&#xff0c;通常可以得到一个还不错的baseline。但…

SSD之硬的不能再硬的硬核解析

本文是对经典论文 SSD: Single Shot MultiBox Detector 的解析&#xff0c;耗时3周完成&#xff0c;万字长文&#xff0c;可能是你能看到的最硬核的SSD教程了&#xff0c;如果想一遍搞懂SSD&#xff0c;那就耐心读下去吧~ 一句话总结SSD效果就是&#xff1a;比YOLO快一点且准很…

C语言学习及应用笔记之五:C语言typedef关键字及其使用

在C语言中有一个typedef关键字&#xff0c;其用来定义用户自定义类型。当然&#xff0c;并不是真的创造了一种数据类型&#xff0c;而是给已有的或者符合型的以及复杂的数据类型取一个我们自己更容易理解的别名。总之&#xff0c;可以使用typedef关键字定义一个我们自己的类型名…

Modbus协议栈开发笔记之五:Modbus RTU Slave开发

Modbus在串行链路上分为Slave和Master&#xff0c;这一节我们就来开发Slave。对于Modbus RTU从站来说&#xff0c;需要实现的功能其实与Modbus TCP的服务器端是一样的。其操作过程也是一样的。首先接收到主站的访问命令&#xff0c;对该命令报文进行解析&#xff0c;这里我们也…

Modbus协议栈开发笔记之六:Modbus RTU Master开发

这一节我们来封装最后一种应用&#xff08;Modbus RTU Master应用&#xff09;&#xff0c;RTU主站的开发与TCP客户端的开发是一致的。同样的我们也不是做具体的应用&#xff0c;而是实现RTU主站的基本功能。我们将RTU主站的功能封装为函数&#xff0c;以便在开发具体应用时调用…

PID控制器开发笔记之十三:单神经元PID控制器的实现

神经网络是模拟人脑思维方式的数学模型。神经网络是智能控制的一个重要分支&#xff0c;人们针对控制过程提供了各种实现方式&#xff0c;在本节我们主要讨论一下采用单神经元实现PID控制器的方式。 1、单神经元的基本原理 单神经元作为构成神经网络的基本单位&#xff0c;具…

基于STM32L476的锂电池SOC检测

便携式设备由于使用需求而配备了锂电池&#xff0c;但使用过程中需要掌握电源的状态才能保证设备正常运行。而且在电池充放电的过程中&#xff0c;监控电池的充放电状态也是保证设备安全的需要。 1、硬件设计 电池SOC检测是一个难题&#xff0c;有很多的模型和检测电路。但对…

C语言学习及应用笔记之六:C语言extern关键字及其使用

在C语言中&#xff0c;修饰符extern用在变量或者函数的声明前&#xff0c;用来以标识变量或者函数的定义在别的文件中&#xff0c;提示编译器遇到此变量或者函数时&#xff0c;在其它文件中寻找其定义。extern关键字的用法有几种&#xff0c;我们下面对其进行说明。 1、extern…

C语言学习及应用笔记之七:C语言中的回调函数及使用方式

我们在使用C语言实现相对复杂的软件开发时&#xff0c;经常会碰到使用回调函数的问题。但是回调函数的理解和使用却不是一件简单的事&#xff0c;在本篇我们根据我们个人的理解和应用经验对回调函数做简要的分析。 1、什么是回调函数 既然谈到了回调函数&#xff0c;首先我们…

STM32与SHT1X温湿度传感器通讯

在这次项目开发中应用到了SHT1X温湿度传感器&#xff0c;该系列有SHT10、SHT11和SHT15&#xff0c;属于Sersirion温湿度传感器家族中的贴片封装系列。包括一个电容性聚合体测湿敏感元件、一个用能隙材料制成的测温元件&#xff0c;传感器内部有一个精度高达14为位的A/D转换器。…

STM32与MS5837压力传感器的I2C通讯

MS5837压力传感器是一种可用于电路板上&#xff0c;适用于检测10-1200mbar压力范围的传感器&#xff0c;灵敏度非常高&#xff0c;理论上能够检测到0.01mbar的压力变化&#xff0c;实际使用过程中测试并无明显的变化。 MS5837采用I2C总线通讯&#xff0c;与STM32的MCU可以实现…

STM32F0使用LL库实现MS5536C通讯

在本次项目中&#xff0c;限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑&#xff0c;而且自带的Flash空间也非常有限&#xff0c;所以我们选择了LL库实现。在本文中我们说明一下&#xff0c;使用LL库实现MS5536C的SPI通讯。 1、MS5536C简述 MS5536C是…

STM32F0使用LL库实现DMA方式AD采集

在本次项目中&#xff0c;限于空间要求我们选用了STM32F030F4作为控制芯片。这款MCU不但封装紧凑&#xff0c;而且自带的Flash空间也非常有限&#xff0c;所以我们选择了LL库实现。在本文中我们将介绍基于LL库的ADC的DMA采集方式。 1、概述 这次我们使用DMA方式实现对AD的采集…