广西民族大学高级人工智能课程—头歌实践教学实践平台-YOLO算法的损失函数

代码文件

from keras import backend as K
 
 
def xy_loss(object_mask, raw_pred, box_loss_scale, raw_true_xy, mf):
    """
    object_mask: 真实置信度
    raw_true_xy: 真实xy
    raw_pred: 预测结果,包含坐标以及置信度和分类结果([x, y, w, h, c, a1, a2, a3...])
    box_loss_scale: box比例
    """
    #********* Begin *********#
    xy_loss = object_mask*box_loss_scale*K.binary_crossentropy(raw_true_xy,raw_pred[...,0:2],from_logits=True)
 
    #********* End *********#
    return K.sum(xy_loss) / mf
def wh_loss(object_mask, raw_pred, box_loss_scale, raw_true_wh, mf):
    """
    object_mask: 真实置信度
    raw_true_xy: 真实wh
    raw_pred: 预测结果,包含坐标以及置信度和分类结果([x, y, w, h, c, a1, a2, a3...])
    box_loss_scale: box比例
    """
    #********* Begin *********#
    wh_loss = object_mask*box_loss_scale*0.5*K.square(raw_true_wh - raw_pred[...,2:4])
 
    #********* End *********#
    return K.sum(wh_loss) / mf
 
 
def confidence_loss(object_mask, raw_pred, ignore_mask, mf):
    confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[..., 4:5], from_logits=True) + \
                          (1 - object_mask) * K.binary_crossentropy(object_mask, raw_pred[..., 4:5],
                                                                    from_logits=True) * ignore_mask
    return K.sum(confidence_loss) / mf
 
 
def class_loss(object_mask, raw_pred, true_class_probs, mf):
    class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[..., 5:], from_logits=True)
    return K.sum(class_loss) / mf
 
 
def loss_sum(loss, raw_pred, y_true, raw_true_xy, raw_true_wh, l, ignore_mask, mf):
    # 真实物体置信度
    object_mask = y_true[l][..., 4:5]
    # 真实物体分类
    true_class_probs = y_true[l][..., 5:]
 
    box_loss_scale = 2 - y_true[l][..., 2:3] * y_true[l][..., 3:4]  # 2-w*h
 
    xy_l = xy_loss(object_mask, raw_pred, box_loss_scale, raw_true_xy, mf)
    wh_l = wh_loss(object_mask, raw_pred, box_loss_scale, raw_true_wh, mf)
    confidence_l = confidence_loss(object_mask, raw_pred, ignore_mask, mf)
    class_l = class_loss(object_mask, raw_pred, true_class_probs, mf)
    loss += xy_l + wh_l + confidence_l + class_l
    return loss

题目描述

任务描述

本关任务:了解YOLO算法的损失函数概念,使用代码实现。

相关知识

YOLO v1损失函数

YOLO V1损失函数组成如下所示:

λcoord ​i=0∑S2​j=0∑B​1ijobj ​[(xi​−x^i​)2+(yi​−y^​i​)2]

+λcoord ​i=0∑S2​j=0∑B​1ijobj ​[(wi​​−w^i​​)2+(hi​​−h^i​​)2]

+i=0∑S2​j=0∑B​1ijobj ​(Ci​−C^i​)2

+λnoobj ​i=0∑S2​j=0∑B​1ijnoobj ​(Ci​−C^i​)2

+i=0∑S2​1iobj ​c∈ classes ∑​(pi​(c)−p^​i​(c))2

1iobj ​代表cell中含有真实物体的中心, pr(object)=1。

损失函数分为三个部分:

  • 坐标误差 为什么宽和高要带根号? 对不同大小的bbox预测中,相比于大bbox预测偏一点,小box预测偏一点更不能忍受。作者用了一个比较取巧的办法,就是将boxwidthheight取平方根代替原本的heightwidth。(主要为了平衡小目标检测预测的偏移)

  • IoU误差(很多人不知道C^i​代表什么)

    其实这里的C^i​分别表示1和0,

    C^i​=Pr( Object )∗1OUpred truth ​

  • 分类误差 这里就是激活函数的输出。

YOLO v2损失函数

YOLO V2损失函数组成如下所示:

losst​=i=0∑W​j=0∑H​k=0∑A​1Max​​IOU< Thresh λnoobj ​∗(−bijko​)2+1t<12800​λprior ​∗r∈(x,y,w,h)∑​( prior kr​−bijkr​)2+1ktruth ​⎝⎜⎛​λcoord ​∗r∈(x,y,w,h)∑​( truth r−bijkr​)2+λobj​∗(IOUtruth k​−bijko​)2∗λclass ​∗(c=1∑c​( truth c−bijkc​)2))​

首先W,H分别指的是特征图(3×13的宽与高,而A指的是先验框数(这里是5),各个λ各个loss部分的权重系数,除了预测有对象的损失函数系数设置为5,其他都为1。

有无对象损失函数计算方法

1MaxIOU< Thresh ​λnoobj ​∗(−bijko​)2+λobj ​∗(IOUtruth k​−bijko​)2​

其中 λobj​=5,λnobj​=1∘​1MaxIOU<Thresh​表示最大的IOU都小于0.6时,取1。boijk​表示0-confidence

YOLOv2中,总共有845个anchor_boxes。在未与true_boxes匹配的anchor_boxes中,与true_boxes的max IOU小于0.6预测无对象,需要计算no_objects_loss其损失。而objects_loss则是与true_boxes匹配的anchor_boxes的预测误差。与YOLOv1不同的是修正系数的改变,YOLO v1中no_objects_lossobjects_loss分别是0.5和1,而YOLO v2中则是1和5。其中 objects_loss = (object_scale * detectors_mask * K.square(best_ious - pred_confidence))和公式表述相类似。

类别损失函数计算方法

+λclass ​∗(c=1∑c​( truth c−bijkc​)2))

均方误差:(1-卷积层预测类别概率)的平方。

坐标损失函数计算方法

+1ktruth ​⎝⎜⎛​λcoord ​∗r∈(x,y,w,h)∑​( truth r−bijkr​)2

和YOLO v1的改动较大:

  • (1)计算x,y的误差由相对于整个图像(416x416)的offset坐标误差的均方改变为相对于gird celloffset坐标误差的均方。并且将YOLOv1w,h取根号处理改为对YOLO v2中长宽放缩因子取log

  • (2)并将修正系数由5改为了1 。

YOLO v3损失函数

YOLO V3损失函数组成如下所示:

 loss ( object )​=λcoord ​i=0∑K×K​j=0∑M​Iijobj ​(2−wi​×hi​)[(xi​−x^i​)2+(yi​−y^​i​)2]+λcoord ​i=0∑K×K​j=0∑M​Iijobj ​(2−wi​×hi​)[(wi​−w^i​)2+(hi​−h^)2]−i=0∑K×K​j=0∑M​Iijobj ​[C^i​log(Ci​)+(1−C^i​)log(1−Ci​)]−λnoobj ​i=0∑K×K​j=0∑M​Iijnoobj ​[C^i​log(Ci​)+(1−C^i​)log(1−Ci​)]−i=0∑K×K​Iijobj ​c∈ classes ∑​[p^​i​(c)log(pi​(c))+(1−p^​i​(c))log(1−pi​(c))]​

图片输入到神经网络后会被分成S*S个网格,每个网格产生B个候选框,每个候选框会经过网络最终得到相应的bounding box。最终得到S*S*B个bounding box。那么就需要利用损失函数确定具体的bounding box计算误差更新权重。

中心点坐标误差

λcoord ​i=0∑K×K​j=0∑M​Iijobj​(2−wi​×hi​)[(xi​−x^i​)2+(yi​−y^​i​)2]

Iijobj ​是真实置信度,(2−wi​×hi​)是box比例,

[(xi​−x^i​)2+(yi​−y^​i​)2]

是求中心点的二值交叉熵。

 
  1. def xy_loss(true_p,true_xy, pred_xy,box_scale):
  2. """
  3. true_p: 真实置信度
  4. true_xy: 真实xy
  5. raw_pred_xy: 预测xy
  6. box_scale: box比例
  7. """
  8. xy_loss = true_p*box_scale*K.binary_crossentropy(true_xy, pred_xy,from_logits=True)

网络输出是 tx​ 和 ty​, 然后通过 σ(tx​) 和 σ(ty​), 再乘以步长,就映射到了 416 * 416大小的图上的目标,所以在计算误差的时候,其实也是用的这一项 σ(tx​)∗ stride 和 σ(ty​)∗stride和真实目标经过resize416 * 416 上的目标的大小,去计算误差。 整个这一项表示的是:当第 i 个网格的第 j 个anchor box负责某一个真实目标时,那么这个anchor box所产生的bounding box就应该去 和真实目标的box去比较,计算得到中心坐标误差。

宽高坐标误差

λcoord ​i=0∑K×K​j=0∑M​Iijobj​(2−wi​×hi​)[(wi​−w^i​)2+(hi​−h^)2]

Iijobj ​是真实置信度,(2−wi​×hi​)是box比例,

[(wi​−w^i​)2+(hi​−h^)2]

是求宽高的均方误差。

 
  1. def xy_loss(true_p,true_wh, pred_wh,box_scale):
  2. """
  3. true_p: 真实置信度
  4. true_xy: 真实wh
  5. raw_pred_xy: 预测wh
  6. box_scale: box比例
  7. """
  8. xy_loss = true_p*box_scale*0.5*K.square(true_wh - pred_wh)

实际上,网络输出的应当是 (tw​) 和 (th​), 所以在计算误差的时候,其实也是用的这一项 (tw​)∗ stride和 (th​)∗ stride和真实目标经过resize之后的值, 去计算误差的。所以可以认为公式里的 wi​ 就是 (tw​)∗ stride等等。 整个这一项表示的是:当第 i 个网格的第j个anchor box负责某一个真实目标时,那么这个anchor box所产生的bounding box就应该去 和真实目标的box去比较,计算得到宽高的误差。

置信度误差

​i=0∑K×K​j=0∑M​Iijobj​[C^i​log(Ci​)+(1−C^i​)log(1−Ci​)]−λnoobj ​i=0∑K×K​j=0∑M​Iijnoobj​[C^i​log(Ci​)+(1−C^i​)log(1−Ci​)]​

置信度误差使用交叉熵来表示。另外需要清楚不管anchor box是否负责某个目标,都会计算置信度误差。因为置信度表示:框出的box内确实有物体的自信程度和框出的box将整个物体的所有特征都包括进来的自信程度。 损失函数分为两部分:有物体,没有物体,其中没有物体损失部分还增加了权重系数。

  • 第一项是:存在对象的bounding box的置信度误差。带有Iijobj​意味着只有"负责"(IOU比较大)预测的那个bounding box的置信度才会计入误差。
  • 第二项是:不存在对象的bounding box的置信度误差。因为不存在对象的bounding box应该老老实实的说"我这里没有对象",也就是输出尽量低的置信度。如果它不恰当的输出较高的置信度,会与真正"负责"该对象预测的那个bounding box产生混淆。其实就像对象分类一样,正确的对象概率最好是1,所有其它对象的概率最好是0。

分类误差

i=0∑S2​Iijobj​c∈ classes ∑​([P^ij​log(Pij​)+(1−P^ij​)log(1−Pij​)]

分类误差也是选择了交叉嫡作为损失函数。当第 i 个网格的第 j 个anchor box负责某一个真实目标时,那么这个anchor box所产生的bounding box才会去计算分类损失函数。

编程要求

根据上述内容提示,在右侧编辑器补充损失函数部分代码。

测试说明


开始你的任务吧,祝你成功!

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值