目标检测这个领域,每年都有新东西出来,但真正能在工业界落地的改进其实不多。GFL(Generalized Focal Loss)算是其中一个——它不是那种"刷点"的论文,而是真正解决了一线工程师天天头疼的问题:为什么我的模型分类得分很高,但框出来的位置就是不准?为什么NMS之后明明该保留的框被滤掉了?这些问题的根源,都指向了传统目标检测中分类分支和回归分支各自为政的设计缺陷。GFL做的事情,就是把这两个分支的监督信号统一起来,让模型学到的质量估计真正反映定位精度。
我第一次接触GFL是在处理一个密集小目标检测的项目上,当时用的还是基于FCOS的架构,分类分支用Focal Loss,回归分支用IoU Loss,训练日志里cls loss降得很漂亮,但mAP就是卡在某个点位上不去。后来把分类分支的one-hot标签换成IoU加权的soft label,再引入DFL把框的回归从"学一个值"变成"学一个分布",效果立竿见影。这篇文章就把GFL的核心机制、代码实现、调参经验和踩过的坑,完整地梳理一遍。
1. 从Focal Loss到GFL:分类分支到底缺了什么
1.1 传统Focal Loss的局限性
Focal Loss本身是为了解决正负样本极度不平衡的问题设计的,公式很简洁:FL(p) = -α(1-p)^γ log(p)。它的核心思想是让模型把注意力集中在难分类的样本上,降低易分类样本的权重。在RetinaNet那篇论文里,这个损失函数确实把one-stage检测器的精度拉到了two-stage的水平。
但问题在于,Focal Loss只关心"这个框是不是目标",它不关心"这个框定位得准不准"。在推理阶段,NMS依赖分类得分来排序和筛选框,如果分类得分不能反映定位质量,就会出现一个尴尬的局面:一个分类得分0.9但IoU只有0.5的框,会排在一个分类得分0.7但IoU有0.85的框前面。NMS一执行,好的框反而被抑制掉了。
这个问题在密集场景下尤其致命。我做过一个交通监控的项目,画面里几十辆车挤在一起,传统Focal Loss训练出来的模型,分类得分和实际定位质量的相关性很差,NMS阈值稍微调高一点就漏检,调低一点就重复框。后来分析预测结果发现,很多分类得分高的框,实际IoU分布非常分散,说明模型根本没有学到"得分高等于定位准"这个映射关系。
1.2 质量估计的两种思路
针对这个问题,学术界主要有两条路线。一条是引入额外的质量估计分支,比如IoU-Net、GCNet这些,让网络单独学一个预测IoU的分支,然后在NMS阶段用这个预测的IoU来加权分类得分。另一条路线就是GFL的思路:不增加额外分支,直接在分类分支的监督信号里嵌入定位质量信息。
GFL的核心洞察是:分类分支的输出不应该是一个one-hot的硬标签,而应该是一个软标签,这个软标签的值就是预测框和真实框之间的IoU。这样一来,分类得分天然就携带了定位质量信息,推理时直接用分类得分做NMS,就能同时考虑分类置信度和定位精度。
这个思路听起来简单,但实现起来有几个关键问题需要解决。第一个问题是,训练初期预测框的IoU波动很大,直接用IoU作为软标签会导致训练不稳定。第二个问题是,分类分支的输出是离散的类别概率,而IoU是连续值,如何让分类分支的输出能够表达连续的质量估计?第三个问题是,回归分支本身也需要改进,传统的回归是学一个确定的值,但框的边界其实存在模糊性,尤其是小目标,边界像素的归属本身就不确定。
1.3 GFL的整体框架
GFL的整体框架可以概括为:分类分支用Quality Focal Loss(QFL)监督,回归分支用Distribution Focal Loss(DFL)监督。QFL解决的是分类得分和定位质量解耦的问题,DFL解决的是框回归的模糊性和不确定性问题。
具体来说,QFL的标签是IoU加权的soft label,损失函数在Focal Loss的基础上做了推广,支持连续值的监督。DFL则把框的回归从"预测一个值"变成"预测一个离散的概率分布",然后通过积分得到最终的框坐标。这个设计的好处是,网络可以表达框边界的不确定性,对于模糊边界的目标,预测的分布会更平坦,对于清晰边界的目标,分布会更尖锐。
在实际部署中,GFL的这些改进几乎不增加推理开销。QFL只是在训练时改变了标签的生成方式,推理时分类分支的输出维度不变。DFL虽然把回归分支的输出从4个值变成了4×(reg_max+1)个值,但通过积分操作后,最终输出的还是4个坐标值,推理速度的影响可以忽略不计。
2. QFL的标签设计:IoU加权到底怎么算
2.1 软标签的生成逻辑
QFL的标签生成是GFL里最容易被忽视但最关键的环节。很多人以为直接把预测框和真实框的IoU拿来当标签就行了,但实际上,训练初期预测框的质量很差,IoU普遍偏低,如果直接用这个IoU作为软标签,会导致正样本的监督信号太弱,模型学不到东西。
GFL论文里的做法是,用当前预测框和真实框的IoU作为软标签,但同时对正样本的选取做了调整。具体来说,正样本的选取还是基于中心采样或者ATSS那套逻辑,但每个正样本的软标签值不是1,而是预测框和真实框的IoU。这个IoU是在训练过程中动态计算的,随着训练进行,预测框越来越准,软标签的值也会逐渐趋近于1。
这里有一个细节需要注意:软标签的IoU计算是在正样本上进行的,负样本的标签还是0。也就是说,QFL只改变了正样本的监督信号,负样本的处理和Focal Loss一样。这样做的好处是,既保留了Focal Loss对负样本的抑制能力,又让正样本的监督信号携带了定位质量信息。
在实际实现中,软标签的生成需要和正样本匹配逻辑配合。以FCOS为例,正样本的选取是基于中心度和尺度的,每个正样本对应一个真实框。在计算QFL损失时,需要先计算预测框和对应真实框的IoU,然后用这个IoU作为软标签。如果预测框和真实框的IoU很低,说明这个正样本的定位质量很差,软标签的值就会很小,QFL会降低这个样本的权重,让模型把注意力集中在定位质量更好的样本上。
2.2 QFL的损失函数推导
QFL的损失函数形式是:QFL(σ) = -|y - σ|^β ((1-y)log(1-σ) + y log(σ)),其中y是软标签(IoU),σ是预测的类别概率,β是调节因子。
这个公式看起来和Focal Loss很像,但有几个关键区别。首先,Focal Loss的标签是离散的0或1,QFL的标签是连续的[0,1]之间的值。其次,Focal Loss的调节因子是(1-p)^γ,QFL的调节因子是|y - σ|^β,这个调节因子是根据预测值和标签的差距来动态调整的。
当预测值σ接近标签y时,|y - σ|^β很小,损失被降低,这符合Focal Loss"降低易分类样本权重"的思想。当预测值σ远离标签y时,|y - σ|^β很大,损失被放大,模型会重点关注这些难样本。这个设计比Focal Loss更灵活,因为Focal Loss的调节因子只和预测值有关,而QFL的调节因子同时考虑了预测值和标签的差距。
β的取值需要根据具体任务调整。在GFL论文里,β=2是一个比较通用的设置。但在实际项目中,如果正样本的IoU普遍偏低,可以适当降低β,让模型不要过度关注那些定位质量很差的样本。我做过一个遥感图像的项目,目标尺度差异很大,小目标的IoU普遍偏低,把β从2降到1.5之后,小目标的召回率有明显提升。
2.3 正样本匹配的配合调整
QFL的效果很大程度上取决于正样本匹配的质量。如果正样本匹配本身就不合理,软标签的IoU再准也没用。在GFL的官方实现里,正样本匹配用的是ATSS(Adaptive Training Sample Selection),这个策略的核心思想是根据目标的统计特性自适应地确定正样本的IoU阈值。
ATSS的具体做法是:对于每个真实框,计算所有候选anchor和它的IoU,然后计算这些IoU的均值和标准差,把均值加标准差作为阈值,IoU大于这个阈值的anchor作为正样本。这个策略的好处是,对于不同尺度和形状的目标,正样本的选取是自适应的,不需要手动调IoU阈值。
在实际使用中,ATSS和QFL的配合需要注意一点:ATSS选出来的正样本,IoU分布可能比较分散,有些正样本的IoU很低。这时候QFL的软标签会把这些低IoU样本的权重降低,相当于自动过滤掉了质量差的正样本。这个机制在训练初期特别有用,因为训练初期预测框的质量普遍很差,如果没有QFL的软标签机制,这些低质量正样本会引入大量噪声。
3. DFL的分布建模:让框回归学会表达不确定性
3.1 传统回归的确定性问题
传统的框回归是让网络直接预测一个坐标值,比如中心点偏移和宽高,然后用L1、L2或者IoU Loss来监督。这种做法的假设是,每个框的边界是确定的,网络只需要学会预测这个确定的值就行了。
但实际情况是,框的边界往往是不确定的。尤其是小目标,边界像素的归属本身就很模糊,一个像素的差异可能导致IoU变化很大。另外,遮挡、运动模糊、标注误差等因素也会导致框的边界存在不确定性。传统的确定性回归无法表达这种不确定性,网络只能学到一个"平均"的预测值,对于模糊边界的目标,预测的框往往不够准确。
DFL的思路是,把框的回归从"预测一个值"变成"预测一个分布"。具体来说,对于框的每条边,网络预测一个长度为reg_max+1的离散概率分布,然后通过积分得到最终的坐标值。这个分布可以表达边界的不确定性:如果分布很尖锐,说明网络对边界很确定;如果分布很平坦,说明网络对边界不确定。
3.2 DFL的积分计算与实现细节
DFL的积分计算是:对于每条边,预测的分布是p(i),i从0到reg_max,最终的坐标值是sum(i * p(i))。这个计算过程是可微的,可以通过反向传播训练。
reg_max的取值需要根据数据集的尺度分布来定。在GFL论文里,reg_max=16是一个比较通用的设置,意味着每条边的预测范围是0到16个像素(相对于特征图尺度)。如果数据集中小目标比较多,可以适当减小reg_max,让分布更集中在小范围内。如果大目标比较多,可以增大reg_max。
在实际实现中,DFL的损失函数是交叉熵损失,监督信号是目标坐标在离散分布上的投影。具体来说,对于真实坐标y,它落在两个离散值i和i+1之间,DFL的损失是让网络预测的分布在这两个离散值上的概率尽可能大。这个设计和分类任务里的label smoothing有点像,但DFL的监督信号是连续的,不是简单的平滑。
这里有一个实现上的坑需要注意:DFL的积分计算需要保证分布的和为1,所以在预测分布之后需要做softmax。另外,积分计算时使用的离散值i是整数,但真实坐标y是浮点数,所以需要做线性插值。在GFL的官方实现里,这部分逻辑封装在DistributionFocalLoss类里,使用的时候直接调用就行。
3.3 DFL在小目标检测中的实际表现
小目标检测一直是目标检测的难点,DFL在小目标上的表现尤其值得关注。我做过一个对比实验,在同一个数据集上,分别用传统的L1 Loss和DFL训练,其他配置完全一样。结果DFL在小目标上的AP提升了大约3个点,在中大目标上的提升不明显。
分析原因,主要是小目标的边界不确定性更大。对于小目标,一个像素的偏移可能导致IoU变化超过10%,传统的L1 Loss会让网络学到一个"折中"的预测值,而DFL可以让网络表达这种不确定性,预测的分布会更平坦,积分后的坐标值更接近真实值的期望。
但DFL也不是万能的。如果数据集的标注质量很差,框的边界本身就不准,DFL学到的分布会非常平坦,积分后的坐标值可能偏离真实值。这种情况下,需要先清洗标注数据,或者用一些标注质量评估的方法过滤掉低质量标注。
另外,DFL的reg_max设置需要和特征图的尺度匹配。如果reg_max设置得太大,分布会过于分散,积分后的坐标值精度会下降。如果reg_max设置得太小,分布会过于集中,无法表达大目标的边界不确定性。在实际项目中,我通常会根据数据集中目标尺度的分布,用网格搜索的方式确定reg_max的最优值。
4. GFL在实际项目中的调参经验
4.1 损失权重的平衡策略
GFL的损失函数由三部分组成:QFL、DFL和GIoU Loss。这三部分的权重需要仔细平衡,否则容易出现某个分支主导训练的情况。
在GFL的官方配置里,QFL的权重是1.0,DFL的权重是0.25,GIoU的权重是2.0。这个配置在COCO数据集上表现不错,但在实际项目中需要根据任务特点调整。
如果分类任务比较难(比如类别很多、类间差异小),可以适当提高QFL的权重,让模型更关注分类。如果定位任务比较难(比如小目标多、遮挡严重),可以适当提高DFL和GIoU的权重。我做过一个工业质检的项目,缺陷目标的边界很模糊,把DFL的权重从0.25提高到0.5之后,定位精度有明显提升。
需要注意的是,损失权重的调整不是孤立的。提高QFL的权重会间接影响定位分支的训练,因为分类得分和定位质量是耦合的。在实际调参时,我通常先固定DFL和GIoU的权重,调整QFL的权重让分类精度达到一个合理水平,然后再调整DFL和GIoU的权重优化定位精度。
4.2 学习率和训练周期的配合
GFL的训练对学习率比较敏感。因为QFL的软标签是动态变化的,训练初期软标签的IoU普遍偏低,如果学习率太大,模型会过度拟合这些低质量样本。训练后期软标签的IoU逐渐升高,如果学习率太小,模型收敛速度会很慢。
在GFL的官方实现里,用的是余弦退火的学习率调度,初始学习率0.01,最终学习率0.0001。这个配置在COCO上训练36个epoch效果不错。但在实际项目中,如果数据集比较小,需要适当减小初始学习率,避免过拟合。如果数据集比较大,可以适当增大初始学习率,加快收敛。
另外,GFL的训练周期需要根据数据集的大小和难度来定。COCO数据集有11.8万张训练图片,训练36个epoch是比较合理的。如果数据集只有几千张图片,训练36个epoch可能会过拟合,通常训练12到24个epoch就够了。我做过一个只有3000张图片的项目,训练18个epoch之后验证集精度就开始下降了。
4.3 正样本匹配的调优
正样本匹配的质量直接影响GFL的训练效果。在GFL的官方实现里,用的是ATSS匹配策略,这个策略在大多数情况下表现不错,但在某些特殊场景下需要调整。
如果数据集中小目标比较多,ATSS的默认参数可能会导致小目标的正样本太少。这时候可以适当降低ATSS的topk参数,让更多的小目标anchor被选为正样本。如果数据集中大目标比较多,可以适当提高topk参数,避免大目标的正样本过多导致训练不平衡。
另外,ATSS的候选anchor选取是基于anchor和真实框的IoU,如果anchor的尺度设置不合理,ATSS的效果会大打折扣。在实际项目中,我通常先用k-means聚类分析数据集中目标尺度的分布,然后根据聚类结果设置anchor的尺度和长宽比。这个步骤虽然简单,但对最终精度的影响很大。
5. 踩坑实录:GFL训练中常见的异常与排查
5.1 损失不收敛的排查链路
GFL训练中最常见的问题是损失不收敛,表现为QFL或DFL的损失值震荡或者持续上升。遇到这种情况,我通常按照以下链路排查。
第一步,检查软标签的IoU计算是否正确。QFL的软标签是预测框和真实框的IoU,如果IoU计算有误(比如坐标顺序搞反了),软标签的值会完全错误,导致QFL的损失异常。排查方法是打印几个正样本的软标签值,看是否在合理范围内(0到1之间,且随着训练进行逐渐增大)。
第二步,检查DFL的积分计算是否正确。DFL的积分是sum(i * p(i)),如果softmax的维度搞错了,或者积分的范围不对,DFL的损失会异常。排查方法是打印几个预测框的分布,看分布的和是否为1,积分后的坐标值是否在合理范围内。
第三步,检查损失权重的配置。如果QFL的权重过大,分类分支会主导训练,DFL和GIoU的损失会被压制,导致定位精度上不去。如果DFL的权重过大,定位分支会主导训练,分类精度会下降。排查方法是分别打印三个损失的值,看是否有某个损失明显大于其他两个。
第四步,检查学习率是否过大。GFL对学习率比较敏感,如果学习率过大,损失会震荡。排查方法是把学习率降低一个数量级,看损失是否变得平稳。
5.2 分类得分与IoU相关性差的处理
GFL的核心目标是让分类得分和IoU正相关,如果训练完之后发现相关性仍然很差,说明QFL没有起到应有的作用。这种情况通常有几个原因。
第一个原因是软标签的β参数设置不当。如果β太大,QFL会过度关注低IoU样本,导致分类得分普遍偏低。如果β太小,QFL对低IoU样本的抑制不够,分类得分和IoU的相关性会变差。排查方法是画一个散点图,横轴是分类得分,纵轴是IoU,看两者的相关性。如果散点图很分散,说明β需要调整。
第二个原因是正样本匹配的质量太差。如果正样本的IoU普遍很低,软标签的值会很小,QFL的监督信号会很弱。排查方法是统计正样本的IoU分布,如果均值低于0.3,说明正样本匹配需要优化。
第三个原因是训练周期不够。QFL的软标签是动态变化的,需要足够的训练周期才能让分类得分和IoU的相关性建立起来。如果训练周期太短,相关性可能还没建立起来就停止训练了。排查方法是延长训练周期,看相关性是否提升。
5.3 DFL分布坍缩的应对
DFL训练中偶尔会出现分布坍缩的问题,表现为预测的分布退化成one-hot分布,即所有概率集中在一个离散值上。这会导致DFL失去表达不确定性的能力,退化成传统的确定性回归。
分布坍缩的原因通常是DFL的损失权重过大,或者reg_max设置得太小。如果DFL的权重过大,网络会过度优化DFL的损失,导致分布过于尖锐。如果reg_max太小,分布的动态范围不够,也容易坍缩。
应对方法是适当降低DFL的权重,或者增大reg_max。另外,可以在DFL的损失里加一个小的熵正则项,鼓励分布保持一定的平坦度。这个技巧在GFL的官方实现里没有,但在实际项目中很有效。我通常加一个权重为0.01的熵正则项,分布坍缩的问题基本不会再出现。
6. GFL与其他检测框架的集成实践
6.1 在YOLO系列中集成GFL
YOLO系列是目前工业界用得最多的检测框架,把GFL集成到YOLO里是一个很实际的需求。YOLOv8及之后的版本,分类分支用的是BCE Loss,回归分支用的是DFL(YOLOv8已经内置了DFL),所以集成GFL的主要工作是把分类分支的BCE Loss换成QFL。
具体做法是:在训练时,对于每个正样本,计算预测框和真实框的IoU,用这个IoU作为软标签,然后用QFL计算分类损失。负样本的处理和原来一样,用BCE Loss。这个改动在YOLOv8的代码里只需要修改损失函数的计算部分,不需要改动网络结构。
实测下来,在YOLOv8上集成QFL之后,mAP有大约1到2个点的提升,尤其是在密集场景下提升更明显。但需要注意的是,YOLOv8的正样本匹配策略和GFL官方实现里的ATSS不完全一样,集成QFL时需要确保正样本的IoU计算和匹配逻辑对齐。
6.2 在FCOS中集成GFL
FCOS是GFL官方实现的基础框架,集成GFL相对简单。FCOS的分类分支用的是Focal Loss,回归分支用的是GIoU Loss,把这两个损失分别换成QFL和DFL就行了。
在FCOS中集成GFL需要注意一点:FCOS的正样本匹配是基于中心度的,每个正样本对应一个真实框。在计算QFL的软标签时,需要确保正样本和真实框的对应关系是正确的。另外,FCOS的回归分支输出的是距离四个边的偏移量,DFL的reg_max需要根据特征图的尺度来设置。
实测下来,在FCOS上集成GFL之后,mAP有大约2到3个点的提升,小目标的提升更明显。但训练时间会增加,因为DFL的积分计算比传统的回归计算要慢一些。
6.3 在DETR类框架中的适配思路
DETR类框架和传统的anchor-based框架差异很大,GFL的集成需要做一些适配。DETR的分类分支用的是交叉熵损失,回归分支用的是L1 Loss,而且DETR的匹配是二分图匹配,不是基于IoU的。
在DETR中集成GFL的思路是:在二分图匹配之后,对于匹配上的正样本,用预测框和真实框的IoU作为软标签,替换原来的one-hot标签,然后用QFL计算分类损失。回归分支可以保留L1 Loss,也可以换成DFL,但DFL的积分计算需要适配DETR的回归输出格式。
这个适配目前还没有看到成熟的实现,主要是因为DETR的训练本身就不太稳定,引入QFL的软标签可能会加剧不稳定性。如果要在DETR中尝试GFL,建议先用小规模数据集验证,确认训练稳定后再扩大规模。
7. 一些实战中的零散心得
关于GFL的软标签,有一个细节值得注意:软标签的IoU计算应该用预测框和真实框的IoU,而不是用anchor和真实框的IoU。有些实现里为了省事,直接用anchor的IoU作为软标签,这样会导致软标签和预测框的质量脱节,QFL的效果大打折扣。
关于DFL的reg_max,如果数据集中目标的尺度跨度很大,可以考虑用多个reg_max,不同尺度的特征图用不同的reg_max。这个技巧在GFL的官方实现里没有,但在实际项目中很有效。我通常让浅层特征图用较小的reg_max(比如8),深层特征图用较大的reg_max(比如16),这样既能保证小目标的精度,又能表达大目标的边界不确定性。
关于训练时的数据增强,GFL对Mosaic和MixUp这类强增强比较敏感。因为强增强会改变目标的边界,导致软标签的IoU计算不准确。在实际项目中,我通常会在训练后期关闭Mosaic和MixUp,让模型在干净的数据上微调几个epoch,这样能提升最终的精度。
关于推理时的NMS,GFL的分类得分已经携带了定位质量信息,所以NMS的阈值可以适当调高。传统的NMS阈值通常是0.5,用GFL之后可以调到0.6甚至0.7,这样能减少重复框,同时不会漏检。这个调整在密集场景下效果特别明显。
最后说一个部署时的注意事项:GFL的DFL分支在推理时需要做积分计算,这个计算在GPU上很快,但在一些边缘设备上可能会成为瓶颈。如果部署在算力受限的设备上,可以考虑把DFL的积分计算简化,比如只取分布的最大值对应的离散值,而不是做完整的积分。这样会损失一些精度,但推理速度会快很多。