L2 loss
RPN网络中对于边框的预测是一个回归问题,通常可以选择平方损失函数,即L2损失。但是当预测值与目标值相差很大时,容易产生梯度爆炸。
L2 loss =
L1 loss
我们可以采用稍微缓和一点的绝对损失函数,即L1损失。它随着误差线性增长,而不是平方增长。但这个函数在0点处导数不存在,因此可能会影响收敛。
L1 loss =
Smoooh L1 Loss
针对上述两个损失的优缺点,我们使用一个分段函数来作为RPN网络的损失函数。此函数在0点附近使用平方损失函数,这样使得它更加平滑,因此被称为平滑L1损失函数,即:Smoooh L1 Loss,表达式如下:
通常情况下,我们还会增加一个参数来控制平滑的区域,则表达式变为如下形式:
Faster-rcnn中的损失函数
Faster-rcnn中RPN网络的损失函数为分类损失与回归损失的总和,其表达式如下:
分类损失使用交叉熵损失函数计算,需要注意的是分类损失计算的是所有样本的平均损失,参数就是样本总数量,隐含在输入参数中,通常为256。
回归损失则使用上述的Smoooh L1 Loss计算,这里我们以此源码中的Smooth L1 loss实现为例进行说明:
def _smooth_l1_loss(bbox_pred, bbox_targets, bbox_inside_weights, bbox_outside_weights, sigma=1.0, dim=[1]):
#RPN训练时,σ = 3(Faster-rCNN训练时,σ = 1)
sigma_2 = sigma ** 2
#ti - ti*
box_diff = bbox_pred - bbox_targets
#只有前景才计算损失,背景不计算损失
in_box_diff = bbox_inside_weights * box_diff
abs_in_box_diff = torch.abs(in_box_diff)
smoothL1_sign = (abs_in_box_diff < 1. / sigma_2).detach().float()
in_loss_box = torch.pow(in_box_diff, 2) * (sigma_2 / 2.) * smoothL1_sign \
+ (abs_in_box_diff - (0.5 / sigma_2)) * (1. - smoothL1_sign)
#乘以回归损失的权重,没有前景(fg)也没有后景(bg)的为0,其他为1/(bg+fg)=1/256
out_loss_box = bbox_outside_weights * in_loss_box
loss_box = out_loss_box
for i in sorted(dim, reverse=True):
loss_box = loss_box.sum(i)
loss_box = loss_box.mean()
return loss_box
- 是一个向量,表示在RPN训练阶段,anchor相对于gt(Ground Truth,即目标所在的真实框)预测的偏移量。对应文章中的:dx(A),dy(A),dw(A),dh(A)
- 是与维度相同的向量,表示在RPN训练阶段,anchor相对于gt实际的偏移量。对应文章中的:tx,ty,tw,th
- 对于每一个anchor 计算完部分后还要乘以,有物体时(positive)为1,没有物体(negative)时为0,意味着只有前景才计算损失,背景不计算损失。即为代码中的bbox_inside_weights。
- 论文中是feature map的尺寸(600*1000的图片,s16,则约为2400),然后将取为10。此时分类损失和回归损失的权重基本相同( 为 256,/约为240)。但是在实际的代码中直接将取为正负样本的总数(256,batch size),然后将取为1,这样相当于直接使分类损失和回归损失的权重相同。因此不需要额外设置。即为代码中的bbox_outside_weights。没有前景(fg)也没有后景(bg)的为0,其他为1/(bg+fg)=1/256。
参考文章:https://blog.csdn.net/Mr_health/article/details/84970776