首页 / 资讯中心 / 文章详情

YOLOv3锚框跨尺度分配调优:从聚类先验到检测精度提升

YOLOv3锚框跨尺度分配调优:从聚类先验到检测精度提升 ★ FEATURED ARTICLE
1. 从锚框的先天缺陷说起为什么人工设计先验框总是不够用如果你自己动手训练过YOLOv3大概率经历过这样的场景模型在训练集上loss降得挺漂亮mAP也还行但一到实际推理小目标漏检严重或者某些长宽比奇特的物体死活框不准。排查半天数据增强、学习率、backbone最后发现问题出在一个最容易被忽视的地方——锚框anchor box的尺寸设计。YOLOv3相比v2最大的改动之一就是引入了多尺度预测在三个不同分辨率的特征图上分别做检测。每个尺度分配3个锚框一共9个。这9个锚框的宽高不是网络学出来的而是在训练开始前通过聚类算法从数据集里统计出来的固定值。也就是说锚框是先验知识是人为设定好之后写进配置文件里的。问题就出在这里。很多人在跑自己的数据集时直接拿COCO的9个锚框来用或者随便跑一次k-means聚类就完事。结果就是锚框和你的数据分布不匹配导致正样本匹配数量少、回归目标不合理、小目标被大锚框吃掉。这不是调参能救的是先验框本身的匹配度问题。标题里提到的九锚框维度先验跨尺度分配说的就是这件事9个锚框的宽高维度是通过聚类得到的先验而它们如何分配到三个不同尺度的特征图上直接决定了检测性能的上限。这篇文章我会从锚框的生成逻辑、跨尺度分配策略、匹配机制、以及实际调优经验几个角度把这个问题彻底讲透。2. YOLOv3的三尺度检测架构与锚框分配逻辑2.1 三个尺度特征图分别负责什么YOLOv3的backbone是Darknet-53输入416×416的图像经过多次下采样后会输出三个不同尺度的特征图特征图尺度下采样倍数网格大小感受野主要负责目标尺度132倍13×13最大大目标尺度216倍26×26中等中目标尺度38倍52×52最小小目标每个尺度上每个网格预测3个边界框。所以总共是 (13×13 26×26 52×52) × 3 10647 个预测框。这个数字很关键因为后面做正负样本匹配时是在这10647个框里筛选正样本的。三个尺度的特征图通过FPN结构进行融合深层特征上采样后与浅层特征concat这样浅层的高分辨率信息能帮助小目标检测深层的语义信息能帮助大目标分类。这个设计本身没问题问题在于——每个尺度上那3个锚框的尺寸是怎么定的2.2 锚框的本质聚类出来的统计先验YOLOv3的锚框不是随机初始化然后让网络学的而是用k-means聚类在训练集的GT框上统计出来的。具体做法是提取训练集中所有标注框的宽高 (w, h)用k-means聚类k9距离度量不用欧氏距离而是用 IoU 相关的度量d(box, centroid) 1 - IoU(box, centroid)聚类得到9个簇中心就是9个锚框的宽高为什么用1-IoU而不是欧氏距离因为欧氏距离对框的大小敏感——一个大框和一个小框的欧氏距离可能很大但它们的IoU可能并不低。用1-IoU能更好地反映框的形状相似度这才是锚框匹配真正关心的。聚类完成后9个锚框按面积从小到大排序然后平均分成3组分别分配给三个尺度。这就是跨尺度分配的字面含义。2.3 为什么是平均分而不是按需分这里有个很多人没注意到的细节YOLOv3官方代码里9个锚框排序后是均匀分成3组的。比如COCO上的9个锚框是(10,13), (16,30), (33,23), (30,61), (62,45), (59,119), (116,90), (156,198), (373,326)分组结果是小尺度52×52(10,13), (16,30), (33,23)中尺度26×26(30,61), (62,45), (59,119)大尺度13×13(116,90), (156,198), (373,326)这个分组逻辑是小特征图感受野大配大锚框大特征图感受野小配小锚框。听起来合理但均匀分组并不一定最优。如果你的数据集里小目标特别多小锚框那一组可能不够用如果目标尺寸分布很集中某些锚框就是浪费。实操提示官方分组是排序后每3个一组但你可以根据数据分布手动调整分组。比如把面积相近的锚框分到同一个尺度而不是机械地按排序切分。3. 锚框与GT的匹配机制正样本是怎么选出来的3.1 匹配的核心规则YOLOv3的正样本匹配规则说起来简单对每个GT框计算它和所有锚框的IoU取IoU最大的那个锚框作为正样本。但实际实现里有个容易忽略的细节——匹配是在锚框层面做的不是在预测框层面做的。具体流程是对每个GT框计算它与9个锚框的IoU注意这里用的是GT的宽高和锚框的宽高不考虑位置找出IoU最大的锚框记为best anchor在best anchor对应的那个尺度上找到GT中心点落在的那个网格该网格的该锚框位置就是正样本这里有个关键点一个GT只匹配一个锚框。如果两个GT的best anchor是同一个它们会分别匹配到不同的网格因为中心点位置不同。但如果两个GT中心点落在同一个网格且best anchor相同就会冲突——YOLOv3的处理是后者覆盖前者这在实际中很少发生但小目标密集场景下需要注意。3.2 为什么不用IoU阈值筛选YOLOv2用的是IoU阈值比如0.5就算正样本YOLOv3改成了取最大IoU。这个改动的原因是阈值法会导致正样本数量不稳定有些GT可能找不到超过阈值的锚框就变成负样本了这对小目标特别不友好。取最大IoU保证了每个GT至少有一个正样本不会出现漏匹配。但代价是如果锚框设计得不好最大IoU可能也很低比如只有0.2这时候正样本的回归目标会很大训练不稳定。这就是锚框匹配度问题的核心锚框和GT的IoU越高回归目标越小训练越容易。如果锚框和GT的IoU普遍偏低网络需要学一个很大的偏移量收敛慢且容易过拟合。3.3 跨尺度分配对匹配的影响回到跨尺度分配。假设你的数据集里有一批中等大小的目标宽高大概是(80, 60)。如果锚框分组是均匀切分的这个尺寸可能落在中尺度和大尺度的边界上。如果它被分到了大尺度13×13那么13×13的网格很粗中心点定位精度低大尺度的锚框尺寸偏大IoU可能不如中尺度但匹配规则是取最大IoU所以它可能还是匹配到中尺度的锚框这里就出现了一个矛盾锚框的跨尺度分配是固定的但匹配是动态的。如果分配不合理某些尺度上的锚框可能很少被匹配到相当于浪费了。4. 锚框匹配度不足的典型症状与诊断方法4.1 症状一小目标漏检严重这是最常见的症状。表现是图像里的小物体比如远处的行人、小动物检测不出来或者置信度很低。排查时先看锚框统计训练集里小目标的宽高分布看最小的3个锚框是否覆盖了这个分布如果小目标的宽高比锚框还小那IoU会很低正样本质量差我遇到过的一个案例某数据集里大量目标宽高在(8, 10)左右但最小锚框是(10, 13)IoU只有0.6左右。虽然不算太低但小目标的回归目标偏大训练后期loss震荡。后来把最小锚框改成(6, 8)小目标mAP直接涨了4个点。4.2 症状二某些尺度沉默训练时观察每个尺度的正样本数量。如果某个尺度的正样本数远少于其他尺度说明这个尺度的锚框和GT匹配度低。正常情况下三个尺度的正样本数应该大致均衡因为目标尺寸分布通常也是分散的。诊断方法在训练代码里加一行统计打印每个尺度的正样本数量。如果13×13尺度的正样本数只有52×52的十分之一那大锚框可能设计得太大了。4.3 症状三回归loss不收敛YOLOv3的回归loss用的是MSE后来很多实现改成IoU loss。如果锚框和GT的IoU普遍低回归目标tx, ty, tw, th的数值会很大MSE loss就会很大梯度也大训练容易震荡。一个经验判断如果训练前几个epoch的回归loss比分类loss大一个数量级大概率是锚框匹配度问题。4.4 诊断工具锚框-IoU热力图最直观的诊断方法是画一张热力图横轴是9个锚框纵轴是GT框按面积排序每个格子填IoU值。这样一眼就能看出哪些锚框被冷落了哪些GT找不到好锚框。这个图用Pythonmatplotlib十几行代码就能画出来比看loss曲线直观得多。我每次换数据集都会先画这张图基本能提前预判训练效果。5. 重新聚类与跨尺度分配的实操调优5.1 聚类前的数据准备聚类用的数据是训练集的GT框但有几个坑要注意不要用验证集或测试集的GT锚框是训练先验用验证集数据会泄露信息过滤掉极端框宽高小于3像素或大于图像尺寸的框可能是标注错误会污染聚类考虑数据增强如果训练时用了随机缩放、裁剪聚类时最好也在增强后的数据上做否则锚框和实际训练分布不匹配我通常的做法是先跑一遍数据增强流程把增强后的GT框收集起来再做聚类。这样得到的锚框更贴近实际训练时的分布。5.2 k-means聚类的参数选择k9是YOLOv3的默认值但不是必须的。如果你的数据集目标尺寸分布很集中k可以小一点比如6如果分布很分散k可以大一点比如12但要注意每个尺度的锚框数要相应调整。聚类的初始化方法也有讲究。随机初始化可能导致局部最优建议用k-means初始化或者多跑几次取最优。距离度量用1-IoU这个前面说过了。聚类完成后一定要可视化验证。把聚类中心和GT框的宽高散点画在一起看聚类中心是否覆盖了主要分布区域。如果某些区域没有聚类中心说明k太小或聚类没收敛。5.3 跨尺度分配的手动调整策略聚类得到9个锚框后默认是按面积排序后均匀分3组。但你可以根据数据分布手动调整数据特点调整策略小目标多小尺度多分配锚框比如4个中尺度3个大尺度2个大目标多大尺度多分配小尺度少分配尺寸分布均匀保持3-3-3有极端长宽比目标确保某个尺度有对应的长宽比锚框调整后要重新验证每个尺度的正样本数量是否均衡mAP是否有提升。5.4 锚框的微调从聚类到实际使用聚类得到的锚框是统计值实际使用时可以微调。比如聚类结果是(12.3, 15.7)你可以取整成(12, 16)或者根据经验调整。微调的幅度不要太大否则就失去聚类的意义了。还有一个技巧锚框的宽高比。YOLOv3的锚框是直接存宽高值但有些实现会存宽高比和面积。如果你的数据集里目标宽高比很集中比如都是1:1或2:1可以专门设计几个对应宽高比的锚框。6. 锚框调优中的常见误区与避坑经验6.1 误区一直接套用COCO锚框这是新手最容易犯的错。COCO的锚框是针对COCO数据集的80类目标统计的你的数据集如果类别不同、拍摄场景不同分布可能完全不一样。我见过有人做人脸检测直接用COCO锚框结果小尺度锚框(10,13)比人脸还大检测效果惨不忍睹。记住锚框是数据相关的换数据集必须重新聚类。6.2 误区二聚类后不验证聚类算法跑完就完事不检查结果。有时候k-means会收敛到局部最优得到的锚框集中在某个区域其他区域没有覆盖。一定要画图验证看聚类中心是否合理。6.3 误区三忽略锚框和特征图尺度的对应关系前面说过小特征图配大锚框。但有些人调整锚框时只改数值不改分组导致大锚框被分到小尺度上。这样小尺度的网格很密但锚框很大IoU反而低。6.4 误区四锚框数量越多越好增加锚框数量确实能提高匹配度但也会增加计算量和过拟合风险。YOLOv3的9个锚框是精度和速度的平衡点。如果非要增加建议先增加尺度数比如4个尺度而不是单纯增加每个尺度的锚框数。6.5 一个实用的调优流程我总结的锚框调优流程是统计训练集GT框的宽高分布画散点图用k-means聚类k9距离用1-IoU可视化聚类结果检查覆盖情况按面积排序均匀分3组分配到三个尺度训练一个短周期比如10个epoch观察每个尺度的正样本数和loss如果某个尺度正样本太少手动调整分组重复5-6直到三个尺度均衡最终训练对比mAP这个流程走下来通常能比默认锚框提升2-5个mAP小目标提升更明显。7. 从锚框到检测上限一些个人体会锚框这个东西说大不大说小不小。它不像backbone那样引人注目也不像loss函数那样有理论深度但它直接决定了正样本的质量而正样本质量又直接决定了检测性能的上限。我见过太多人花大量时间调学习率、换backbone、加数据增强却忽略了锚框这个最基础的东西。跨尺度分配这个点官方代码里就是简单排序后切分但实际数据分布往往不是均匀的。手动调整分组让每个尺度的锚框更贴合该尺度负责的目标尺寸这个操作成本很低但收益很直接。还有一个体会是锚框调优不是一劳永逸的。如果你在训练过程中用了多尺度训练random resize锚框的匹配度会随输入尺寸变化。这时候可以考虑在多个尺度上分别聚类或者用相对尺寸锚框宽高除以输入尺寸来做匹配。最后分享一个小技巧如果你不确定锚框调得对不对可以做一个锚框消融实验——用默认锚框和调优后的锚框各训一个模型其他配置完全一样对比mAP。这个对比能直观告诉你锚框调优值不值得。根据我的经验在自定义数据集上这个对比的差距通常在3-8个mAP之间小目标密集的数据集差距更大。
阅读完成 · 觉得有帮助?
咨询建站