全文目录
专栏链接:深度学习和论文精读
本文包含损失函数的介绍以及代码实现,如有问题请及时指出~
1 损失函数概念
损失函数是监督学习中的一个核心概念,用于衡量模型预测的结果与真实值之间的差距。在机器学习模型的训练过程中,损失函数计算预测值与实际标签之间的误差,训练的目标就是通过优化算法(如梯度下降)最小化这个损失函数,从而使模型在给定数据集上的表现尽可能好。
损失函数有多种形式,选择哪一种通常取决于具体的任务(如回归、分类、序列预测等)和数据的特性。本文将介绍一些常用的损失函数以及代码实现。
符号说明
在下文中,若无特殊说明,则满足如下假设:
y
i
y_i
yi是样本
i
i
i的真实值,
y
^
i
\hat{y}_i
y^i是样本的预测值,
N
N
N是样本总数。
代码说明
# 默认导入如下的包
import numpy as np
import torch
import torch.nn as nn
2 分类损失
2.1 交叉熵(Cross-Entropy Loss)
交叉熵损失是一种常用于分类问题的损失函数,特别适合度量两个概率分布之间的差异。在机器学习分类任务中,它通常用于比较真实标签的分布和模型预测的概率分布,可用于二分类和多分类任务中。
公式:
L
C
E
=
−
∑
i
=
1
C
y
i
log
(
p
i
)
L_{CE} = -\sum_{i=1}^C y_i \log(p_i)
LCE=−i=1∑Cyilog(pi)
代码:
# 初始化交叉熵损失
criterion = nn.CrossEntropyLoss()
# 创建示例张量数据(注意,PyTorch的CrossEntropyLoss不需要独热编码)
# 真实标签是类的索引
y_true = torch.tensor([1, 2])
# 模型输出的原始得分(logits),不需要softmax
y_pred = torch.tensor([[2.0, 1.0, 0.1],
[0.1, 0.3, 2.5]])
loss = criterion(y_pred, y_true)
print(loss.item())
def cross_entropy_loss(y_true, y_pred):
# 小的常数,防止log(0)
epsilon = 1e-12
y_pred = np.clip(y_pred, epsilon, 1. - epsilon)
# 计算交叉熵
ce = -np.sum(y_true * np.log(y_pred)) / y_true.shape[0]
return ce
# 示例数据 需要时One-Hot编码
y_true = np.array([[0, 1, 0],
[0, 0, 1]])
y_pred = np.array([[0.05, 0.95, 0],
[0.1, 0.8, 0.1]])
loss = cross_entropy_loss(y_true, y_pred)
print(loss)
2.2 Focal Loss
Focal Loss是一种专为解决类别不平衡问题设计的损失函数,最初由Tsung-Yi Lin等人在2017年的论文《Focal Loss for Dense Object Detection》中提出。这种损失函数主要用于密集的对象检测任务中,其核心思想是降低简单样本的损失贡献,同时增加难分类或错误分类样本的损失权重。详解可查看focal loss详解。
FL
(
p
t
)
=
−
α
t
(
1
−
p
t
)
γ
log
(
p
t
)
\text{FL}(p_t) = -\alpha_t (1 - p_t)^\gamma \log(p_t)
FL(pt)=−αt(1−pt)γlog(pt)
其中:
- p t p_t pt是模型对正确类别的预测概率。
- α t \alpha_t αt 是平衡正负样本的权重参数,可以根据类别的频率动态调整。
- γ \gamma γ 是聚焦参数,它决定了容易分类的样本在总损失中的权重下降的速度。
代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
class FocalLoss(nn.Module):
def __init__(self, alpha=0.25, gamma=2.0):
super(FocalLoss, self).__init__()
self.alpha = alpha
self.gamma = gamma
def forward(self, inputs, targets):
BCE_loss = F.binary_cross_entropy_with_logits(inputs, targets, reduction='none')
pt = torch.exp(-BCE_loss) # Prevents nans when probability 0
F_loss = self.alpha * (1-pt)**self.gamma * BCE_loss
return F_loss.mean()
# 示例使用
inputs = torch.randn(10, requires_grad=True)
targets = torch.empty(10).random_(2)
loss_func = FocalLoss()
loss = loss_func(inputs, targets)
print("Loss:", loss.item())
3 回归损失
3.1 绝对误差(L1 Loss、Mean Absolute Error,MAE)
L1 损失计算模型预测值与真实值之间差的绝对值的平均数。尤其适用于需要稳健处理异常值的场合。此外,它也常用于特征选择中,因为它倾向于生成稀疏解,即许多参数值会变为零。
公式:
L
1
=
1
N
∑
i
=
1
N
∣
y
i
−
y
^
i
∣
L1 = \frac{1}{N} \sum_{i=1}^N |y_i - \hat{y}_i|
L1=N1i=1∑N∣yi−y^i∣
代码:
# 示例数据
y_true = torch.tensor([3, -0.5, 2, 7, 10])
y_pred = torch.tensor([2.5, 0.0, 2, 8, 20])
# Pytorch
l1_loss = nn.L1Loss(reduction='mean')
loss = l1_loss(y_pred, y_true)
print(loss.item())
# 2.4000000953674316
# 示例数据
y_true = np.array([3, -0.5, 2, 7, 10])
y_pred = np.array([2.5, 0.0, 2, 8, 20])
# 自定义函数
def l1_loss(y_true, y_pred):
return np.mean(np.abs(y_true - y_pred))
loss = l1_loss(y_true, y_pred)
print(loss)
# 2.4
参数设置:
nn.L1Loss(reduction=‘mean’)
- ‘mean’:计算损失平均值。
- ‘sum’:计算损失总和。
- ‘none’:返回每个样本的损失数组。
3.2 均方误差(L2 Loss、Mean Squared Error,MSE)
L2损失计算模型预测值与实际目标值之间差异的平方的平均值。MSE 损失函数旨在最小化预测误差的平方和,有助于放大较大误差的影响,因此对于提高模型对异常数据的敏感性特别有效。
公式:
L
2
=
1
N
∑
i
=
1
n
(
y
i
−
y
^
i
)
2
L2 = \frac{1}{N} \sum_{i=1}^n (y_i - \hat{y}_i)^2
L2=N1i=1∑n(yi−y^i)2
代码:
# 示例数据
y_true = torch.tensor([3, -0.5, 2, 7, 10])
y_pred = torch.tensor([2.5, 0.0, 2, 8, 20])
# Pytorch
l2_loss = nn.MSELoss(reduction='mean')
loss = l2_loss(y_pred, y_true)
print(loss.item())
# 20.299999237060547
# 示例数据
y_true = np.array([3, -0.5, 2, 7, 10])
y_pred = np.array([2.5, 0.0, 2, 8, 20])
# 自定义函数
def l2_loss(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
loss = l2_loss(y_true, y_pred)
print(loss)
# 20.3
参数设置同L1 Loss
3.3 Smooth L1 Loss(Huber Loss)
Smooth L1 Loss是均方误差(MSE)损失和平均绝对误差(MAE)损失的结合,出自Fast RCNN 。设计目的是减少对异常值的敏感性,同时避免在训练时由于梯度爆炸的问题。
公式:
SmoothL1Loss
(
x
)
=
{
0.5
×
x
2
if
∣
x
∣
<
1
,
∣
x
∣
−
0.5
otherwise
.
\text{SmoothL1Loss}(x) = \begin{cases} 0.5 \times x^2 & \text{if } |x| < 1, \\ |x| - 0.5 & \text{otherwise}. \end{cases}
SmoothL1Loss(x)={0.5×x2∣x∣−0.5if ∣x∣<1,otherwise.
其中,
x
x
x是预测值与真实值之间的差值。
代码:
# 示例数据
predictions = torch.tensor([0.5, 1.5, 2.0])
targets = torch.tensor([0.0, 1.0, 2.5])
# 创建Smooth L1 Loss函数对象
loss_function = nn.SmoothL1Loss()
loss = loss_function(predictions, targets)
print(loss.item())
4 边界框损失
边框回归损失(Bounding Box Regression Loss)是在计算机视觉任务中,尤其是在目标检测模型中使用的一种损失函数。这种损失函数帮助模型学习如何准确地预测目标的位置和大小。在目标检测任务中,模型需要预测每个目标的边界框,通常包括框的中心点坐标、高度和宽度。以下是几种常用的Loss的对比:
IoU Loss:考虑了重叠面积,归一化坐标尺度;
GIoU Loss:考虑了重叠面积,基于IOU解决边界框不相交时loss等于0的问题;
DIoU Loss:考虑了重叠面积和中心点距离,基于IOU解决GIOU收敛慢的问题;
CIoU Loss:考虑了重叠面积、中心点距离、纵横比,基于DIOU提升回归精确度;
EIoU Loss:考虑了重叠面积,中心点距离、长宽边长真实差,基于CIOU解决了纵横比的模糊定义,并添加Focal Loss解决BBox回归中的样本不平衡问题。
4.1 IoU Loss
交并比损失(Intersection over Union Loss,简称IoU损失)是一种在目标检测中广泛使用的损失函数,用于优化预测的边界框(bounding box)与真实边界框之间的匹配度。IoU损失是通过直接衡量预测框和真实框之间的重叠区域来实现这一目标的。
公式:
IoU
=
1
−
IOU
=
1
−
∣
A
∩
B
∣
∣
A
∪
B
∣
\text{IoU} = 1 - \text{IOU} = 1 - \frac{|A \cap B|}{|A \cup B|}
IoU=1−IOU=1−∣A∪B∣∣A∩B∣
其中,
A
A
A和
B
B
B分别代表预测框和真实框的区域,
∣
A
∩
B
∣
|A \cap B|
∣A∩B∣表示两个框的交集面积,而
∣
A
∪
B
∣
|A \cup B|
∣A∪B∣表示两个框的并集面积。
代码:
#来源:https://blog.csdn.net/weixin_43334693/article/details/131304963
def IoU(box1, box2):
b1_x1, b1_y1, b1_x2, b1_y2 = box1
b2_x1, b2_y1, b2_x2, b2_y2 = box2
xx1 = np.maximum(b1_x1, b2_x1) #计算交集矩形左边界的 x 坐标(较大的 x1 值)
yy1 = np.maximum(b1_y1, b2_y1) # 计算交集矩形上边界的 y 坐标(较大的 y1 值)
xx2 = np.minimum(b1_x2, b2_x2) #计算交集矩形右边界的 x 坐标(较小的 x2 值)
yy2 = np.minimum(b1_y2, b2_y2) #计算交集矩形下边界的 y 坐标(较小的 y2 值)
w = np.maximum(0.0, yy2 - yy1) #计算交集矩形的宽度。如果yy2小于yy1,则交集矩形不存在,宽度为0
h = np.maximum(0.0, xx2 - xx1) #算交集矩形的高度。如果xx2小于xx1,则交集矩形不存在,高度为0
inter = w * h
IoU = inter/((b1_x2-b1_x1)*(b1_y2-b1_y1) + (b2_x2-b2_x1)*(b2_y2-b2_y1) - inter)
print("IoU: ", IoU)
if __name__ == "__main__":
box1 = np.array([100, 100, 210, 210])
box2 = np.array([150, 150, 230, 220])
IoU(box1, box2)
缺点(参考路人贾’ω’):
- 如果两个框没有相交,根据定义,IoU=0,不能反映两者的距离大小(重合度)。同时因为loss=0,没有梯度回传,无法进行学习训练。(如图(a)所示)
- 当预测框和真实框的交并比相同,但是预测框所在位置不同,因为计算出来的损失一样,所以这样并不能判断哪种预测框更加准确。(如图(b)(c)所示)
4.2 GIoU Loss
论文原文: 《Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression》
GIoU在原始IoU的基础上加入了一个额外的度量,该度量衡量的是边界框与包围这两个框的最小闭合矩形之间的相对关系。GIoU不仅计算交集和并集,还考虑了边界框之间的空间关系,即使它们之间没有交集。
公式:
GIoU
=
IoU
−
∣
C
∣
−
∣
A
∪
B
∣
∣
C
∣
\text{GIoU} = \text{IoU} - \frac{|C| - |A \cup B|}{|C|}
GIoU=IoU−∣C∣∣C∣−∣A∪B∣
其中,
∣
C
∣
|C|
∣C∣表示最小闭合矩形的面积,而
∣
A
∪
B
∣
|A \cup B|
∣A∪B∣表示两个边界框并集的面积。这个公式直观地展示了广义交并比如何通过考虑最小闭合矩形来改进传统的 IoU计算。
相较于IoU,GIoU见下图(图源路人贾’ω’)。
代码:
#来源:https://blog.csdn.net/weixin_43334693/article/details/131304963
def GIoU(box1, box2):
b1_x1, b1_y1, b1_x2, b1_y2 = box1
b2_x1, b2_y1, b2_x2, b2_y2 = box2
# IOU
xx1 = np.maximum(b1_x1, b2_x1)
yy1 = np.maximum(b1_y1, b2_y1)
xx2 = np.minimum(b1_x2, b2_x2)
yy2 = np.minimum(b1_y2, b2_y2)
inter_w = np.maximum(0.0, yy2 - yy1)
inter_h = np.maximum(0.0, xx2 - xx1)
inter = inter_w * inter_h
Union = (b1_x2-b1_x1)*(b1_y2-b1_y1) + (b2_x2-b2_x1)*(b2_y2-b2_y1) - inter
# GIOU
C_xx1 = np.minimum(b1_x1, b2_x1)
C_yy1 = np.minimum(b1_y1, b2_y1)
C_xx2 = np.maximum(b1_x2, b2_x2)
C_yy2 = np.maximum(b1_y2, b2_y2)
C_area = (C_xx2 - C_xx1) * (C_yy2 - C_yy1)
IOU = inter / Union
GIOU = IOU - abs((C_area-Union)/C_area)
print("GIOU:", GIOU)
if __name__ == "__main__":
box1 = np.array([100, 100, 210, 210])
box2 = np.array([150, 150, 230, 220])
GIoU(box1, box2)
缺点(参考路人贾’ω’):
见上图,当目标框完全包裹预测框的时候, IoU 和 GIoU 的值都一样,此时 GIoU 退化为 IoU,无法区分其相对位置关系。
4.3 DIoU Loss
论文原文:《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》
DIoU Loss是一种在目标检测中用来优化边界框预测的损失函数。这种损失函数基于IoU损失的基础上,进一步考虑了两个边界框中心点之间的距离,以改进边界框的回归精度。DIoU Loss旨在解决当两个边界框不重叠时,IoU损失和GIoU损失可能无法提供有效梯度的问题,同时更加注重边界框中心的对齐。
公式:
DIoU Loss
=
1
−
IoU
+
ρ
2
(
bbox
pred
,
bbox
gt
)
c
2
\text{DIoU Loss} = 1 - \text{IoU} + \frac{\rho^2(\text{bbox}_{\text{pred}}, \text{bbox}_{\text{gt}})}{c^2}
DIoU Loss=1−IoU+c2ρ2(bboxpred,bboxgt)
其中:
- IoU \text{IoU} IoU表示预测边界框( b b o x pred bbox_{\text{pred}} bboxpred)和真实边界框( b b o x gt bbox_{\text{gt}} bboxgt)之间的交并比。
- ρ ( bbox pred , bbox gt ) \rho(\text{bbox}_{\text{pred}}, \text{bbox}_{\text{gt}}) ρ(bboxpred,bboxgt)是预测框和真实框中心点之间的欧氏距离。
- c c c是包括两个边界框的最小闭合框对角线长度,用于归一化中心点距离,确保其与IoU处于相同的尺度。
相较于GoU,DIoU见下图。
DIoU损失用于边界框回归,其中可以直接最小化两个框中心点之间的归一化距离。这里的
c
c
c是覆盖两个框的最小封闭框的对角线长度,而
d
=
ρ
(
b
,
b
g
t
)
d=\rho(b, b^{gt})
d=ρ(b,bgt)是两个框中心点之间的距离。
DIoU便可解决GIoU目标框完全包裹预测框的时候, IoU 和 GIoU 的值都一样的问题。
代码:
#来源:https://blog.csdn.net/weixin_43334693/article/details/131304963
def DIoU(box1, box2):
b1_x1, b1_y1, b1_x2, b1_y2 = box1
b2_x1, b2_y1, b2_x2, b2_y2 = box2
# IOU
xx1 = np.maximum(b1_x1, b2_x1)
yy1 = np.maximum(b1_y1, b2_y1)
xx2 = np.minimum(b1_x2, b2_x2)
yy2 = np.minimum(b1_y2, b2_y2)
inter_w = np.maximum(0.0, xx2 - xx1)
inter_h = np.maximum(0.0, yy2 - yy1)
inter = inter_w * inter_h
Union = (b1_x2 - b1_x1)*(b1_y2 - b1_y1) + (b2_x2 - b2_x1)*(b2_y2 - b2_y1) - inter
# DISTANCE
C_xx1 = np.minimum(b1_x1, b2_x1)
C_yy1 = np.minimum(b1_y1, b2_y1)
C_xx2 = np.maximum(b1_x2, b2_x2)
C_yy2 = np.maximum(b1_y2, b2_y2)
C_area = (C_xx2 - C_xx1) * (C_yy2 - C_yy1)
center_b_x = (b1_x1+b1_x2)/2
center_b_y = (b1_y1+b1_y2)/2
center_gtb_x = (b2_x1+b2_x2)/2
center_gtb_y = (b2_y1+b2_y2)/2
center_distance = (center_gtb_x-center_b_x)**2 + (center_gtb_y-center_b_y)**2
c_distance = (C_xx2 - C_xx1)**2 + (C_yy2 - C_yy1)**2
IOU = inter/Union
DIOU = IOU - center_distance /c_distance
print("DIOU:", DIOU)
if __name__ == "__main__":
box1 = np.array([100, 100, 210, 210])
box2 = np.array([150, 150, 230, 220])
DIoU(box1, box2)
缺点(参考路人贾’ω’):
DIoU考虑了重叠面积和中心点距离,当目标框包裹预测框的时候,直接度量2个框的距离,因此DIoU收敛的更快,但并没有考虑到长宽比。
4.4 CIoU Loss
论文原文:《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》
CIoU Loss是一种在目标检测中使用的进阶边界框回归损失函数。CIoU损失是在DIoU损失的基础上发展出来的,进一步增加了考虑边界框的长宽比匹配,使得损失计算不仅涉及边界框的中心点距离和交并比,还包括它们的形状差异。
公式:
CIoU Loss
=
1
−
IoU
+
ρ
2
(
bbox
pred
,
bbox
gt
)
c
2
+
α
⋅
v
\text{CIoU Loss} = 1 - \text{IoU} + \frac{\rho^2(\text{bbox}_{\text{pred}}, \text{bbox}_{\text{gt}})}{c^2} + \alpha \cdot v
CIoU Loss=1−IoU+c2ρ2(bboxpred,bboxgt)+α⋅v
其中:
- IoU 是预测边界框(bbox_pred)和真实边界框(bbox_gt)的交并比。
- ρ ( bbox pred , bbox gt ) \rho(\text{bbox}_{\text{pred}}, \text{bbox}_{\text{gt}}) ρ(bboxpred,bboxgt)是预测框和真实框中心点之间的欧氏距离。
- c c c是包含两个边界框的最小闭合框对角线的长度,用于归一化中心点距离。
- α \alpha α是一个权重参数,用于调整长宽比惩罚项的重要性,计算为:
- α = v ( 1 − IoU ) + v \alpha = \frac{v}{(1 - \text{IoU}) + v} α=(1−IoU)+vv
- v v v表示预测框和真实框宽高比的一致性,计算为:
- v = 4 π 2 ( arctan w gt h gt − arctan w pred h pred ) 2 v = \frac{4}{\pi^2} \left(\arctan\frac{w_{\text{gt}}}{h_{\text{gt}}} - \arctan\frac{w_{\text{pred}}}{h_{\text{pred}}}\right)^2 v=π24(arctanhgtwgt−arctanhpredwpred)2
代码:
#来源:https://blog.csdn.net/weixin_43334693/article/details/131304963
def CIoU(box1, box2):
b1_x1, b1_y1, b1_x2, b1_y2 = box1
b2_x1, b2_y1, b2_x2, b2_y2 = box2
# IOU
xx1 = np.maximum(b1_x1, b2_x1)
yy1 = np.maximum(b1_y1, b2_y1)
xx2 = np.minimum(b1_x2, b2_x2)
yy2 = np.minimum(b1_y2, b2_y2)
inter_w = np.maximum(0.0, xx2 - xx1)
inter_h = np.maximum(0.0, yy2 - yy1)
inter = inter_w*inter_h
Union = (b1_x2-b1_x1)*(b1_y2-b1_y1) + (b2_x2-b2_x1)*(b2_y2-b2_y1) - inter
IOU = inter/Union
C_xx1 = np.minimum(b1_x1, b2_x1)
C_yy1 = np.minimum(b1_y1, b2_y1)
C_xx2 = np.maximum(b1_x2, b2_x2)
C_yy2 = np.maximum(b1_y2, b2_y2)
# DISTANCE
center_b_x = (b1_x1 + b1_x2)/2
center_b_y = (b1_y1 + b1_y2)/2
center_gtb_x = (b2_x1 + b2_x2)/2
center_gtb_y = (b2_y1 + b2_y2)/2
C_area = (C_xx2-C_xx1)*(C_yy2-C_yy1)
Distance = (center_gtb_x-center_b_x)**2 + (center_gtb_y-center_b_y)**2
Distance_area = Distance/C_area**2
# aspect ratio
pred_w = b1_y2 - b1_y1
pred_h = b1_x2 - b1_x1
gt_w = b2_y2 - b2_y1
gt_h = b2_x2 - b2_x1
v = (4/(np.pi)**2)*(np.arctan(gt_w/gt_h) - np.arctan(pred_w/pred_h))**2
alpha = v/((1-IOU) + v)
CIOU = IOU - Distance_area - alpha*v
print("CIOU:", CIOU)
if __name__ == "__main__":
box1 = np.array([100, 100, 210, 210])
box2 = np.array([150, 150, 230, 220])
CIoU(box1, box2)
缺点(参考路人贾’ω’):
- 如果预测框和gt框的长宽比是相同的,那么长宽比的惩罚项恒为0,不合理
- 观察CIoU中w, h相对于v的梯度,发现这两个梯度是一对相反数,也就是说,w和h不能同时增大或减小,这显然也不够合理的。
4.5 EIoU Loss
论文原文:《Focal and Efficient IOU Loss for Accurate Bounding Box Regression》
EIOU 是在 CIOU 的惩罚项基础上将预测框和真实框的纵横比的影响因子拆开,分别计算预测框和真实框的长和宽,来解决 CIOU 存在的问题。
EIoU包括三个部分:IoU损失、距离损失、高宽损失(重叠面积、中心点举例、高宽比)。高宽损失直接最小化了预测目标边界框和真实边界框的高度和宽度的差异,使其有更快的收敛速度和更好的定位结果。
公式:
L
EIoU
=
L
IoU
+
L
dis
+
L
asp
L_{\text{EIoU}} = L_{\text{IoU}} + L_{\text{dis}} + L_{\text{asp}}
LEIoU=LIoU+Ldis+Lasp
=
1
−
IoU
+
ρ
2
(
b
,
b
g
t
)
c
2
+
ρ
2
(
w
,
w
g
t
)
C
w
2
+
ρ
2
(
h
,
h
g
t
)
C
h
2
= 1 - \text{IoU} + \frac{\rho^2(b, b^{gt})}{c^2} + \frac{\rho^2(w, w^{gt})}{C_w^2} + \frac{\rho^2(h, h^{gt})}{C_h^2}
=1−IoU+c2ρ2(b,bgt)+Cw2ρ2(w,wgt)+Ch2ρ2(h,hgt)
其中:
- L I o U L_{IoU} LIoU是基于交并比的损失。
- L d i s L_{dis} Ldis是基于预测框和真实框中心点之间距离的损失。
- L d i s L_{dis} Ldis是关于预测框和真实框宽高比一致性的损失。
- L a s p L_{asp} Lasp表示预测框和真实框中心点之间的欧氏距离平方。
- ρ ( b , b g t ) \rho(b, b^{gt}) ρ(b,bgt)是包含两个边界框的最小闭合框对角线的长度。
- ρ ( w , w g t ) \rho(w, w^{gt}) ρ(w,wgt)和 ρ ( h , h g t ) \rho(h, h^{gt}) ρ(h,hgt)分别表示宽和高的预测值与真实值之间的差距的平方。
- C w 2 C_w^2 Cw2和 C h 2 C_h^2 Ch2和是宽和高的归一化参数,通常取决于数据集中目标的尺寸分布。
代码:
#来源:https://blog.csdn.net/weixin_43334693/article/details/131304963
def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, EIoU=True, eps=1e-7):
# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
box2 = box2.T
# Get the coordinates of bounding boxes
if x1y1x2y2: # x1, y1, x2, y2 = box1
b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
else: # transform from xywh to xyxy
b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2
# Intersection area
inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
(torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
# Union Area
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
union = w1 * h1 + w2 * h2 - inter + eps
iou = inter / union
if GIoU or DIoU or CIoU or EIoU:
cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width
ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height
if CIoU or DIoU or EIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
(b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center distance squared
if DIoU:
return iou - rho2 / c2 # DIoU
elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
with torch.no_grad():
alpha = v / (v - iou + (1 + eps))
return iou - (rho2 / c2 + v * alpha) # CIoU
elif EIoU:
rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2
rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2
cw2 = cw ** 2 + eps
ch2 = ch ** 2 + eps
return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2)
else: # GIoU https://arxiv.org/pdf/1902.09630.pdf
c_area = cw * ch + eps # convex area
return iou - (c_area - union) / c_area # GIoU
else:
return iou # IoU
参考
损失函数整理(分类和回归)
损失函数:IoU、GIoU、DIoU、CIoU、EIoU、alpha IoU、SIoU、WIoU超详细精讲及Pytorch实现
Pytorch学习之十九种损失函数
常用的损失函数合集