一、网络介绍
YoloX由旷视科技开源,以YoloV3(Darknet53作为backbone)作为基线,最大的区别在于 Decoupled Head,Data Aug,Anchor Free 和样本匹配(SimOTA)这几个方面,另外还提供了完善的代码,并很贴心的提供了部署脚本,真的很友好了。
PDF: https://arxiv.org/pdf/2107.08430.pdf
Code: https://github.com/Megvii-BaseDetection/YOLOX
参考:https://www.zhihu.com/question/473350307
1. Decoupled Head
将检测头解耦无疑会增加运算的复杂度,但经过权衡速度和性能上的得失,最终使用 1个1x1 的卷积先进行降维,并在分类和回归分支里各使用了 2个3x3 卷积,最终仅仅增加一点点参数,YOLOX 在 s,m,l,x 模型速度上的轻微下降也全源自于此。表面上看,解耦检测头提升了 YOLOX 的性能和收敛速度,但更深层次的,它为 YOLO 与检测下游任务的一体化带来可能。如:
- YOLOX + Yolact/CondInst/SOLO ,实现端侧的实例分割
- YOLOX + 34 层输出,实现端侧人体的 17 个关键点检测
2. Data Aug
数据增强方法Mosaic (主要思想是将四张图片进行随机裁剪,再拼接到一张图上作为训练数据,丰富背景的同时变相的增加了BatchSize)经过 YOLOv5 和 v4 的验证,已经证明了其能带来显著涨点。
YoloX为 Mosaic 配上 Copypaste,依然有不小的提升。这样做的原因是:当模型容量足够大的时候,相对于先验知识(各种 tricks,hand-crafted rules ),更多的后验(数据/数据增强)才会产生本质影响。可 Copypaste 的实现依赖于目标的 mask 标注,而 mask 标注在常规的检测业务上是稀缺的资源。而由于 MixUp 和 Copypaste 有着类似的贴图的行为,还不需要 mask 标注,因此可以让 YOLOX 在没有 mask 标注的情况下吃到 Copypaste 的涨点。不过YoloX中的 Mixup,没有原始 Mixup 里的 Bernoulli Distribution 和 Soft Label ,有的仅是 0.5 的常数透明度和 Copypaste 里提到的尺度缩放 ( scale jittering )。 YOLOX 里的 Mixup 有如此明显的涨点,大概是因为它在实现和涨点原理上更接近 Copypaste,而不是原版 Mixup。
注意:要在训练结束前的15个 epoch 关掉 Mosaic 和Mixup ,这可以避免让 YOLOX 训练结果偏离真实分布(Mosaic+Mixup 生成的训练图片,远远脱离自然图片的真实分布,并且 Mosaic 大量的 crop 操作会带来很多不准确的标注框)。
参考:https://github.com/ultralytics/yolov5/issues/2151
3. Anchor Free 与 Label Assignment
至于为什么 YoloX作为Anchor Free但性能不降反升,这与样本匹配有密不可分的联系
-
loss/quality/prediction aware
基于网络自身的预测来计算 anchor box 或者 anchor point 与 gt 的匹配关系,充分考虑到了不同结构/复杂度的模型可能会有不同行为,是一种真正的 dynamic 样本匹配 -
center prior
目标的质心都与目标的几何中心有一定的联系,将正样本限定在目标中心的一定区域内做 loss/quality aware 样本匹配能很好地解决收敛不稳定的问题 -
不同目标设定不同的正样本数量( dynamic k )
Dynamic k 的关键在于如何确定k,有些方法通过其他方式间接实现了动态 k ,比如 ATSS、PAA ,甚至 RetinaNet ,同时,k的估计依然可以是 prediction aware 的,我们具体的做法是首先计算每个目标最接近的10个预测,然后把这个 10 个预测与 gt 的 iou 加起来求得最终的k,很简单有效,对 10 这个数字也不是很敏感,在 5~15 调整几乎没有影响
二、网络实现
参照提供的代码:https://github.com/Megvii-BaseDetection/YOLOX
- 主要网络结构
在yolox目录下的models中找到yolox.py文件,
主要包含YOLOXHead和YOLOPAFPN两块
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Copyright (c) Megvii Inc. All rights reserved.
import torch.nn as nn
from .yolo_head import YOLOXHead
from .yolo_pafpn import YOLOPAFPN
class YOLOX(nn.Module):
"""
YOLOX model module. The module list is defined by create_yolov3_modules function.
The network returns loss values from three YOLO layers during training
and detection results during test.
"""
def __init__(self, backbone=None, head=None):
super().__init__()
if backbone is None:
backbone = YOLOPAFPN()
if head is None:
head = YOLOXHead(80)
self.backbone = backbone
self.head = head
def forward(self, x, targets=None):
# fpn output content features of [dark3, dark4, dark5]
fpn_outs = self.backbone(x)
if self.training:
assert targets is not None
loss, iou_loss, conf_loss, cls_loss, l1_loss, num_fg = self.head(
fpn_outs, targets, x
)
outputs = {
"total_loss": loss,
"iou_loss": iou_loss,
"l1_loss": l1_loss,
"conf_loss": conf_loss,
"cls_loss": cls_loss,
"num_fg": num_fg,
}
else:
outputs = self.head(fpn_outs)
return outputs
- nano tiny s m l x 不同格式模型
YOLOX提供不同版本的模型,主要区别在于修改网络的depth和width,其对应的大小分别为:
self.depth = 0.33 # nano: 0.33, tiny:0.33, s: 0.33, m: 0.67, l: 1.0, x: 1.33 # nano和tiny需调整self.input_size = (416, 416)
self.width = 0.50 # nano: 0.25, tiny: 0.375, s: 0.50, m: 0.75, l: 1.0, x: 1.25
最终影响的是YOLOPAFPN模块
-
部署
在Demo目录下还提供了不同的部署方式,可以依据实际需求进行选择。
以NCNN平台为例,其关键点在于自定义实现YoloV5Focus层:
-
效果
三、训练自己数据
参照docs目录下的train_custom_data.md,训练自己数据主要包含以下几个步骤:
1. 准备数据集
采用labelme标注 利用labelme工程中自带的转换脚本将其转换成coco数据样式
2. 数据存放格式
dataDir
- annotations
- annotations_train.json
- annotations_val.json
- JPEGImages
- *.jpg
备注:按coco标准来讲,JPEGImages目录下还应分成train和val两个目录,这里修改了datasets/coco.py文件,所以没有再区分
# img_file = os.path.join(self.data_dir, self.name, file_name)
img_file = os.path.join(self.data_dir, file_name)
# print("********", os.path.isfile(img_file))
img_file = img_file.replace("\\", "/")
3. 新建自己参数脚本
在根目录下的exps目录下新建Tooth.py,依据实际情况设置相应参数
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import os
from yolox.exp import Exp as MyExp
class Exp(MyExp):
def __init__(self):
super(Exp, self).__init__()
self.depth = 0.33 # s: 0.33, m: 0.67, l: 1.0, x: 1.33
self.width = 0.50 # s: 0.50, m: 0.75, l: 1.0, x: 1.25
self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0]
# Define yourself dataset path
self.data_dir = "/home/heygears/jinhai_zhou/data/2D_detect/tooth"
self.train_ann = "annotations_train.json"
self.val_ann = "annotations_val.json"
self.num_classes = 2 # include background
self.max_epoch = 300
self.data_num_workers = 4
self.eval_interval = 1
self.cls_names = (
"background",
"tooth",
)
4.训练
进入根目录下的tools目录
执行:
python train.py -f ../exps/Tooth.py -d 0 -b 64 --fp16 -o -c /path/to/yolox_s.pth
其中-d后面数字表示GPU编号, -b 后面数字表示批量数据大小, --fp16表示混合精度训练 后面的pth文件为预训练权重
5.测试
修改tools目录下demo.py,添加demo==images参数,支持图片批量测试
执行以下命令进行测试
python demo.py images -f ../exps/Tooth.py -n Tooth -c ../weights/Tooth_s.pth --path ../assets/tooth --conf 0.55 --nms 0.45 --tsize 640 --save_result --device cpu
6.导出模型
在tools目录下,运行export_onnx.py文件
python export_onnx.py -f ../exps/Tooth.py -n Tooth -c ../weights/Tooth_s.pth --output-name ./tooth.onnx
四、常见错误
训练中出现的问题
-
question
RuntimeError: Ninja is required to load C++ extensions -
solution
https://github.com/Megvii-BaseDetection/YOLOX/issues/1454
wget https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip
sudo unzip ninja-linux.zip -d /usr/local/bin/
sudo update-alternatives --install /usr/bin/ninja ninja /usr/local/bin/ninja 1 --force
标签:__,YoloX,py,loss,--,self,YOLOX,---,深度
From: https://www.cnblogs.com/xiaxuexiaoab/p/17748310.html