generalized focal loss V1, V2分析与使用

希望通过本文能了解到:

  1. generalized focal loss的背景和原理;
  2. 代码的实现,如何加在自己的模型中;

generalized focal loss v1- 2020.6.8
generalized focal loss v2- 2020.11.25


1.背景

v1主要解决:

  1. 大多数目标检测模型中,要同时预测目标置信度 s c o r e o b j score_{obj} scoreobj和类别置信度 s c o r e i ( i = 1... n ) score_{i}(i =1...n) scorei(i=1...n),训练的时候分开单独训练,test时却相乘作为nms的目标框质量分, 0.9 ∗ 0.3 > 0.5 ∗ 0.5 0.9*0.3 > 0.5* 0.5 0.90.3>0.50.5;
  2. 目标检测一贯的模式都是直接预测边框参数,会不会太生硬了,如图,两个下边框似乎都还行,标注框就一定绝对正确么?
    在这里插入图片描述

v1贡献:

  1. 提出用一个小数统一代表目标框得分,虽然作者把它解释成了 s c o r e o b j ∗ s c o r e i score_{obj}*score_{i} scoreobjscorei,结果本来目标框 b b o x − s c o r e bbox - score bboxscore,以前的score是两部分,而且不是0,就是1,现在就是一个小数了;
  2. 提出用预测一个分布图来代替习以为常的绝对预测;
  3. 为了训练提出quality focal loss和distribution focal loss来训练;
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • loss定义可以去看论文,大概就是把focal loss只能训练0-1标签的问题改成了可以训练小数label,建议可以手动画下qfl的二维曲线图看看;
  • dfl定义中y是gt_label, y i + 1 y_{i+1} yi+1 y i y_{i} yi是由预测融合出的数的下取整和上取整(间隔取1时),log部分是一个数与一组分布向量的交叉熵。
  • 比较有意思的是df loss,对于一个参数 p j p_{j} pj的预测向量: X = { x i } X = \{x_{i}\} X={xi},则加权系数为 W = { w i } W=\{w_{i}\} W={wi},其中 i = 1... l e n g t h i=1...length i=1...length则:
    p j = X W T p_{j}=XW^T pj=XWT
    有一种多项式组合的感觉,其中 w i = i w_{i}=i wi=i即可,然后在放缩到自己需要的范围。

v2主要解决:

  1. v1中的分布就只是用来融合出一个数,比如宽,高,偏移,作者感觉没完全把信息利用起来;

v2贡献:

  1. 把分布图的信息叠加到了类别预测分支上
  2. 这里得解释的就是gfl的模型可以看做最后的特征输出了两个头,一个输出 b a t c h ∗ c ∗ w ∗ h batch * c* w * h batchcwh的4维目标,一个输出 b a t c h ∗ ( 4 ∗ n ) ∗ w ∗ h batch * (4*n) * w * h batch(4n)wh的偏移信息。这里的4,请参考FCOS模型的定义。想在把第二个的分布信息乘到了第一个类别分的预测上。

在这里插入图片描述

总结:GFL模型把目标框中的点全当做正例计算,不过对于这些正样本框,有的分高,有的分低,使用预测分布来得到参数预测,类似把原本一个数分解成了多个,似乎增强了稳定性,v2中把这种分布预测反哺到置信度的预测中,加快收敛提高精度。


2.代码

由于我要用在********中,所以基本自己换了种写法。

  1. dfl的积分:
    从分布恢复预测的数值。
    自己写的,和原实现做了些改变,主要主要reshape时,保证通道数据的连续性。
    原模型预测4个参数,把reshape中2改成4即可,这里的127是我的输出特征宽度。
    以下同。
    但是解析分布向量时以 hwhwhw…的形式比hhh…www…似乎mAP能高一些,可以多试试
def forward(self, x):
    """
	输入dfl的n * (x*length) * h * w 积分出 n * x * h * w
	"""
	n,c,h,w = x.shape
	# x = x.reshape(n,c//2,2, h, w)
	x = x.reshape(n,2,c//2, h, w)# 一定要主语通道的拆分,如果直接拆成(n,2,h,w,c//2), 模型可能不会收敛,原因是reshape
	x = x.permute(0,1,3,4,2) 
	x = F.softmax(x, dim=4)
	x = F.linear(x, self.project.type_as(x)) * 127 / (lenght-1) # length就是划分成几个,比如8格,最多加权出7,区间[0,length-1]
	return x

2.qfloss

def qfloss(preds, target, beta=2.0):
    scale_factor = (preds - target).abs().pow(beta)
    # binary_cross_entropy_with_logits = sigmoid(preds) + binary_cross_entropy()
    loss = F.binary_cross_entropy_with_logits(preds, target, reduction='none') * scale_factor
    nums = (target==1).sum()
    if nums == 0:
        loss = loss.sum()
    else:
        loss = loss.sum()/ (1e-4 + nums)
    return loss 

分析如下的qfloss公式计算(其中右边括号内由binary_cross_entropy_with_logits直接计算得到):
− ∣ g − p ∣ 2 ∗ ( g ∗ l o g ( p ) + ( 1 − g ) l o g ( 1 − p ) ) -|g-p|^2*(g*log(p) + (1-g)log(1-p)) gp2(glog(p)+(1g)log(1p))
如果gt是小数的,那它将同时被左边的正例loss和右边的负例loss计算,对比focalloss这种0-1的硬计算,这里就像把原本右边负例的一部分loss,挪给了左边正例。
收敛慢了,mAP没看出效果,多试试吧。

  1. dfloss
def dfloss(pred, gt):
    n,c,h,w= pred.shape
    pred = pred.reshape(n,2,c//2, h, w)
    pred = pred.permute(0,1,3,4,2) # 
    mask = (gt>0)

    pos_gt = gt[mask]
    pos_gt = pos_gt * (pred.shape[-1]-1) / 127 # 0-1 -> 0-8 #8得减一  127是特征图最大坐标而非128
    
    pos_pred = pred[mask] 
    
    id_left = pos_gt.long()
    id_right = id_left + 1
    w_left = id_right.float() - pos_gt
    w_right = pos_gt - id_left.float()
    # cross_entropy = softmax + log + cross entropy
    loss_dfl = F.cross_entropy(pos_pred, id_left, reduction='none') * w_left + w_right * F.cross_entropy(pos_pred, id_right, reduction='none')
    loss_dfl = loss_dfl.mean() 
    return loss_dfl
    
  1. v2中的融合模块
    这一块自己还没用过,可以参考源码实现
    取topk的分布预测数值加上它们的mean,过两个卷积通道变成1,直接乘上框质量预测分支,注意是sigmoid以后的。

update:
配合dfl还不错,在小模型上提高收敛速度效果明显;
在大模型上似乎没用,训练完去掉融合分支也没影响…

### 定义这个轻量的融合模块
conf_vector = [nn.Conv2d(4 * self.total_dim, self.reg_channels, 1)]
conf_vector += [self.relu]
conf_vector += [nn.Conv2d(self.reg_channels, 1, 1), nn.Sigmoid()]
self.reg_conf = nn.Sequential(*conf_vector)
###
...
###
...
###
# 取topk的分布预测数值加上它们的mean,过两个卷积通道变成1
if self.add_mean:
    stat = torch.cat([prob_topk, prob_topk.mean(dim=2, keepdim=True)],dim=2)
else:
    stat = prob_topk
quality_score = self.reg_conf(stat.reshape(N, -1, H, W))
cls_score = self.gfl_cls(cls_feat).sigmoid() * quality_score
###
...
###

在这里插入图片描述

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Generalized Focal Loss是一种处理不平衡数据集的损失函数,它在传统的Focal Loss上进行了改进,可以用于多分类和回归任务。YoloV5是一种目标检测算法,它采用一种基于单个神经网络的方法来实现快速而准确的目标检测。结合使用Generalized Focal Loss和YoloV5可以进一步提升目标检测的性能。 在目标检测任务中,不同类别的样本数量往往是不平衡的,一些常见的类别可能会有很多样本,而一些罕见的类别可能只有极少数样本。对于这种情况,使用传统的交叉熵损失函数可能会导致网络偏向于训练样本数量较多的类别,而对于那些样本数量较少的类别则表现不佳。 Generalized Focal Loss采用了类似于Focal Loss的方法来处理不平衡数据集,该方法通过降低容易分类的样本的权重来提高难以分类的样本在训练过程中的重要性。此外,Generalized Focal Loss还添加了一些参数来控制样本难度的权重,这提高了模型对于罕见类别的识别能力。 结合Generalized Focal Loss和YoloV5可以进一步提高目标检测性能。YoloV5现有的版本已经使用Focal Loss来处理类别不平衡的问题,但使用Generalized Focal Loss可以更加灵活地进行参数调节。通过用Generalized Focal Loss替换原有的损失函数,可以减少误分类样本的影响,提高整个模型对于样本数量较少的类别的识别能力,从而进一步提高整个目标检测系统的性能。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值