首先感谢本次参与YOLOX算法复现工作的社区贡献者们 (Github 账号名):
HAOCHENYE、xiaohu2015、zhiqwang、HsLOL、shinya7y
最近 YOLOX 火爆全网,速度和精度相比 YOLOv3、v4 都有了大幅提升,并且提出了很多通用性的 trick,同时提供了部署相关脚本,实用性极强。
近期,MMDetection 开源团队成员也组织进行了相关复现。通过与社区成员的协同开发,不仅让复现过程更加高效,而且社区成员在参与过程中可以不断熟悉算法,熟悉 MMDetection 开发模式。
后续我们也会再次组织相关复现活动,希望社区成员积极参与,共同成长,共同打造更加优异的目标检测框架。
本文内容
1. YOLOX 算法简介
2.YOLOX 复现流程全解析
1. YOLOX 算法简介
官方开源地址:
https://github.com/Megvii-BaseDetection/YOLOX
MMDetection 开源地址(欢迎 star):
GitHub - open-mmlab/mmdetection: OpenMMLab Detection Toolbox and Benchmark
复现相关 projects:
Support of YOLOX · open-mmlab/mmdetection
YOLOX 的主要特性可以归纳为:
· Anchor-free,无需设计 anchor,更少先验,减少复杂超参,推理较高效;
· 提出了 Decoupled Head,参考 FCOS 算法设计解耦了分类和回归分支,同时新增 objectness 回归分支;
· 为了加快收敛以及提高性能,引入了 SimOTA 标签分配策略,其包括两部分 Multi positives 和 SimOTA,Multi positives 可以简单的增加每个 gt 所需的正样本数,SimOTA 基于 CVPR2021 最新的 OTA 算法,采用最优传输理论全局分配每个 gt 的正样本,考虑到 OTA 带来的额外训练代价,作者提出了简化版本的 OTA ,在长 epoch 训练任务中 SimOTA 和 OTA 性能相当,且可以极大的缩小训练代价;
· 参考 YOLOV4 的数据增强策略,引入了 Mosaic 和 MixUp,并且在最后 15 个 epoch 时候关闭这两个数据增强操作,实验表明可以极大地提升性能;
· 基于上述实践,参考 YOLOV5 网络设计思路,提出了 YOLOX-Nano、YOLOX-Tiny、YOLOX-S、YOLOX-M、YOLOX-L 和 YOLOX-X 不同参数量的模型。
2. YOLOX 复现流程全解析
本节目录
2.1 推理精度对齐
2.2 训练精度对齐
2.2.1 优化器和学习率调度器
2.2.2 EMA策略
2.2.3 Dataset
2.2.4 Loss
2.2.5 其他训练 trick
由于篇幅有限,本篇文章将详细呈现【2.1 推理精度对齐】部分,其余内容请关注知乎【OpenMMLab】同步推出的完整内容 ~
本期知乎链接:
https://zhuanlan.zhihu.com/p/398545304
我们简单将 YOLOX 复现过程拆分为 3 个步骤,分别是:(1)推理精度对齐(2)训练精度对齐(3)重构。
#(偷偷注释掉)为了方便将官方开源权重迁移到 MMDetection 中,在推理精度对齐过程中,我们没有修改任何模型代码,而且简单的复制开源代码,分别插入 MMDetection 的 backbone 和 head 文件夹下,这样就只需要简单的替换模型 key 即可重复段落请忽略小编已哭晕。
2.1 推理精度对齐
为了方便将官方开源权重迁移到 MMDetection 中,在推理精度对齐过程中,我们没有修改任何模型代码,而且简单的复制开源代码,分别插入 MMDetection 的 backbone 和 head 文件夹下,这样就只需要简单的替换模型 key 即可。
一个特别需要注意的点:BN 层参数不是默认值 eps=1e-5, momentum=0.1,而是eps=1e-3, momentum=0.03,这个应该是直接参考 YOLOV5。
排除了模型方面的问题(后处理策略我们暂时也没有改),对齐推理精度核心就是分析图片前处理代码。其处理流程非常简单——
# 前处理核心操作
def preproc(image, input_size, mean, std, swap=(2, 0, 1)):
# 预定义输出图片大小
padded_img = np.ones((input_size[0], input_size[1], 3)) * 114.0
# 保持宽高比的 resize
img = np.array(image)
r = min(input_size[0] / img.shape[0], input_size[1] / img.shape[1])
resized_img = cv2.resize(
img,
(int(img.shape[1] * r), int(img.shape[0] * r)),
interpolation=cv2.INTER_LINEAR,
).astype(np.float32)
# 右下 padding
padded_img[: int(img.shape[0] * r), : int(img.shape[1] * r)] = resized_img
# bgr -> rgb
padded_img = padded_img[:, :, ::-1]
# 减均值,除方差
padded_img /= 255.0
if mean is not None:
padded_img -= mean
if std is not None:
padded_img /= std
padded_img = padded_img.transpose(swap)
return padded_img, r
滑动可见完整代码
可以发现,其前处理流程比较简单:先采用保持宽高比的 resize,然后右下 padding 成指定大小输出,最后是归一化。
在 MMDetection 中可以直接通过修改配置文件来支持上述功能:
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=img_scale,
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Pad', size=(640, 640), pad_val=114.0),
dict(type='Normalize', **img_norm_cfg),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img'])
])
]
相关的后处理阈值为:
test_cfg=dict(
score_thr=0.001,
nms=dict(type='nms', iou_threshold=0.65)))
分别对 YOLOX-S 和 YOLOX-Tiny 模型权重在官方源码和 MMDetection 中进行评估,验证是否对齐,结果如下:
注意:由于官方开源代码一直处于更新中,现在下载的最新权重,可能 mAP 不是上表中的值。