查看原文
其他

MMYOLO一站式上手指南,从安装、训练到模型优化全面覆盖

易宁远 OpenMMLab 2024-04-23


本文入选【技术写作训练营】优秀结营作品,作者:易宁远


MMYOLO 是一个基于 PyTorch 和 MMDetection 的 YOLO 系列算法开源工具箱,它是 OpenMMLab 项目的一部分。MMYOLO 定位为 YOLO 系列热门开源库以及工业应用核心库,其中实现了很多 YOLO 系列的算法(YOLOv5、v6、v7 以及 RTMDet-Rotated、RTMDet)。



本文综合多处 MMYOLO 文档,并结合了本人的实践经验,希望可以帮助到大家。

主要参考资料如下:

https://mmyolo.readthedocs.io/zh_CN/latest/get_started/overview.html

https://github.com/open-mmlab/OpenMMLabCourse/blob/main/mmyolo.md



1. 基础测试


这部分主要涉及 MMYOLO 的安装与测试,目的是查看 MMYOLO 是否安装成功。


1.1 安装和验证


安装完成 MMYOLO 后,按照 MMYOLO 文档中的方法进行验证:

文档链接:https://mmyolo.readthedocs.io/zh_CN/latest/get_started/installation.html



1.2  建立软连接


为方便代码调试以及后面的跨库调用模块,参考以下命名完成软连接操作,将 OpenMMLab 其他库链接到 MMYOLO 中:


# 下载 MMYOLOgit clone git@github.com:open-mmlab/MMYOLO.git# 下载 mmenginegit clone https://github.com/open-mmlab/mmengine.git# 下载 mmdetgit clone https://github.com/open-mmlab/mmdetection.git
# 进入 MMYOLO 路径下cd MMYOLO# 建立软链接(win10 也支持软链接了)ln -s ../mmdetection/mmdet mmdetln -s ../mmengine/mmengine mmengine

注意检查更新保持 git clone 的链接为最新的链接地址


完成后可以在 pycharm 等 IDE 中试下能否全局搜索跳转到 DetDataPreprocessor(mmdet 中一个类)。



2. 数据从准备到训练的全流程


2.1 单一类别


2.1.1 数据集获取与划分



数据集获取 


可以直接下载制作好的数据集或者自己制作。MMYOLO 自带了下载脚本,可以下载一些方便验证算法与掌握 MMYOLO 的数据集,并且还贴心地配有后续转化为 coco 格式以及划分数据集的脚本。、MMYOLO 单类别提供了两类数据集:猫猫数据集和气球数据集,猫猫数据集直接为 MMYOLO 配套的 coco 格式,气球数据集需要使用 ./tool 下的数据集转化脚本转换为 coco 形式。下面以下载 MMYOLO 配套猫猫(cat)数据集为例:


python tools/misc/download_dataset.py --dataset-name cat --save-dir ./data/cat --unzip --delete


数据集划分


通常,自定义图片都是一个大文件夹,里面全部都是图片,需要我们自己去对图片进行训练集、验证集、测试集的划分,如果数据量比较少,可以不划分验证集。下面是划分脚本的具体用法:

python tools/misc/coco_split.py --json ${COCO label json 路径} \                                --out-dir ${划分 label json 保存根路径} \                                --ratios ${划分比例} \                                [--shuffle] \                                [--seed ${划分的随机种子}]


其中:

  • --ratios:划分的比例,如果只设置了 2 个,则划分为 trainval + test;如果设置为 3 个,则划分为 train + val + test。支持两种格式 —— 整数、小数:


    整数:按比例进行划分,代码中会进行归一化之后划分数据集。例子:--ratio 2 1 1(代码里面会转换成 0.5 0.25 0.25) or --ratio 3 1(代码里面会转换成 0.75 0.25)

    小数:划分为比例。如果加起来不为 1 ,则脚本会进行自动归一化修正。例子:--ratio 0.8 0.1 0.1 or --ratio 0.8 0.2

  • --shuffle: 是否打乱数据集再进行划分。

  • --seed:设定划分的随机种子,不设置的话自动生成随机种子。


例子:


python tools/misc/coco_split.py --json ./data/cat/annotations/annotations_all.json \                                --out-dir ./data/cat/annotations \                                --ratios 0.8 0.2 \                                --shuffle \                                --seed 10


2.1.2 转 coco 格式后数据集操作



数据集格式(不一定为这个文件夹结构,训练和测试的 json 格式对即可)



  • annotation_all.json 是所有的标注。trainval.json 和 test.json 是从 annotation_all.json 中划分出的训练验证集和测试集

  • iamge 文件夹下,是所有图片

  • class_with_id.txt 是类别的 id 标号和类别名的对应关系,如:1 cat


数据集检查和可视化


脚本1,检查数据集:


使用下面的命令可以将 COCO 的 label 在图片上进行显示,这一步可以验证刚刚转换是否有问题:


python tools/analysis_tools/browse_coco_json.py --img-dir ./data/cat/images --ann-file ./data/cat/annotations/annotations_all.json


效果:逐一显示标注后的图片,显示图片数量和类别名称、数量。(Ctrl+C 强行终止显示)



更多参数可参考:

https://mmyolo.readthedocs.io/zh-cn/latest/useful_tools/browse_dataset.html


脚本2,可视化数据集:


脚本 tools/analysis_tools/dataset_analysis.py 能够帮助用户得到数据集的分析图。该脚本可以生成 4 种分析图:


  • 显示类别和 bbox 实例个数的分布图:show_bbox_num

  • 显示类别和 bbox 实例宽、高的分布图:show_bbox_wh

  • 显示类别和 bbox 实例宽/高比例的分布图:show_bbox_wh_ratio

  • 基于面积规则下,显示类别和 bbox 实例面积的分布图:show_bbox_area


以本教程 cat 数据集 的 config 为例。


注:本脚本需要使用 config 文件,按本文档行文顺序,目前并未讲如何写对应数据集的 config 文件,所以该脚本可以在下一小节有了 config 文件 后再尝试。


查看训练集数据分布情况:


python tools/analysis_tools/dataset_analysis.py configs/custom_dataset/yolov5_s-v61_syncbn_fast_1xb32-100e_cat.py      --out-dir work_dirs/dataset_analysis_cat/train_dataset



查看验证集数据分布情况:


python tools/analysis_tools/dataset_analysis.py configs/custom_dataset/yolov5_s-v61_syncbn_fast_1xb32-100e_cat.py \                                                --out-dir work_dirs/dataset_analysis_cat/val_dataset \                                                --val-dataset


更多内容可参考:https://mmyolo.readthedocs.io/zh-cn/latest/useful_tools/dataset_analysis.html


2.1.3 配置文件的复用更改



MMYOLO 根据配置文件(写有各种字段的 py 文件)调整网络结构与训练测试流程,配置文件是“总控制器”。训练自己的模型可以复制一份原有配置文件(./config/xxx/yyy.py)然后进行修改。这里暂不涉及对模型结构修改(对模型结构的修改见第四节)。复用配置文件需要改


  • 数据集根路径(即存放image和ann的总目录)。注意:最后要有/结尾

  • 训练、测试等json文件路径

  • 图片子路径前缀(从根路径到图片文件夹的路径)

  • class name(注意:('cat',)单个种类最后要空个,否则不认识为tuple类型)

  • class_num

  • metainfo:指定类别名称和对应的bbox颜色

  • 以上为配合数据集需要修改的,其他参数根据个人需要进行修改。例如:


    batch size

    workers

    max_epochs :训练多少epoch

    train_batch_size_per_gpu :根据gpu和数据情况确定

    其他


参考:

# 基于该配置进行继承并重写部分配置_base_ = 'yolov5_s-v61_syncbn_fast_8xb16-300e_coco.py'
data_root = './data/cat/' # 数据集根路径class_name = ('cat', ) # 数据集类别名称num_classes = len(class_name) # 数据集类别数# metainfo 必须要传给后面的 dataloader 配置,否则无效# palette 是可视化时候对应类别的显示颜色# palette 长度必须大于或等于 classes 长度metainfo = dict(classes=class_name, palette=[(20, 220, 60)])
# 基于 tools/analysis_tools/optimize_anchors.py 自适应计算的 anchoranchors = [    [(68, 69), (154, 91), (143, 162)],  # P3/8    [(242, 160), (189, 287), (391, 207)],  # P4/16    [(353, 337), (539, 341), (443, 432)]  # P5/32]# 最大训练 40 epochmax_epochs = 40# bs 为 12train_batch_size_per_gpu = 12# dataloader 加载进程数train_num_workers = 4
# 加载 COCO 预训练权重load_from = 'https://download.openmmlab.com/MMYOLO/v0/yolov5/yolov5_s-v61_syncbn_fast_8xb16-300e_coco/yolov5_s-v61_syncbn_fast_8xb16-300e_coco_20220918_084700-86e02187.pth'  # noqa
model = dict(    # 固定整个 backbone 权重,不进行训练    backbone=dict(frozen_stages=4),    bbox_head=dict(        head_module=dict(num_classes=num_classes),        prior_generator=dict(base_sizes=anchors)    ))
train_dataloader = dict(    batch_size=train_batch_size_per_gpu,    num_workers=train_num_workers,    dataset=dict(        data_root=data_root,        metainfo=metainfo,        # 数据集标注文件 json 路径        ann_file='annotations/trainval.json',        # 数据集前缀        data_prefix=dict(img='images/')))
val_dataloader = dict(    dataset=dict(        metainfo=metainfo,        data_root=data_root,        ann_file='annotations/test.json',        data_prefix=dict(img='images/')))
test_dataloader = val_dataloader
_base_.optim_wrapper.optimizer.batch_size_per_gpu = train_batch_size_per_gpu
val_evaluator = dict(ann_file=data_root + 'annotations/test.json')test_evaluator = val_evaluator
default_hooks = dict(    # 每隔 10 个 epoch 保存一次权重,并且最多保存 2 个权重    # 模型评估时候自动保存最佳模型    checkpoint=dict(interval=10, max_keep_ckpts=2, save_best='auto'),    # warmup_mim_iter 参数非常关键,因为 cat 数据集非常小,默认的最小 warmup_mim_iter 是 1000,导致训练过程学习率偏小    param_scheduler=dict(max_epochs=max_epochs, warmup_mim_iter=10),    # 日志打印间隔为 5    logger=dict(type='LoggerHook', interval=5))# 评估间隔为 10train_cfg = dict(max_epochs=max_epochs, val_interval=10)


注意:定义的所有参数要在复用的 config 文件中被调用才会起作用。例如:


定义并更改了 num_classes 值,就要在需要该值的 bbox_head 的 head_module=dict(num_classes=num_classes) 中被调用。对 metainfo 和 max_epochs 的修改同理,都需要在 dict 中被调用。


另外,对于需要 anchor 的算法:anchor 参数可通过 MMYOLO 提供的脚本生成:


YOLOv5 是 一个 anchor-based 算法,需要对 anchor 进行自适应计算,anchor-free 的模型可以跳过此步骤。脚本 tools/analysis_tools/optimize_anchors.py 支持 YOLO 系列中三种锚框生成方式,分别是 k-means、Differential Evolution、v5-k-means。


本示例使用的是 YOLOv5 进行训练,使用的是 640 x 640 的输入大小,使用 v5-k-means 进行描框的优化:


python tools/analysis_tools/optimize_anchors.py configs/custom_dataset/yolov5_s-v61_syncbn_fast_1xb32-100e_cat.py                                                --algorithm v5-k-means                                                --input-shape 640 640                                                --prior-match-thr 4.0                                                --out-dir work_dirs/dataset_analysis_cat


更多内容可参考:

https://mmyolo.readthedocs.io/zh-cn/latest/useful_tools/optimize_anchors.html


2.1.4 训练前的检查



检查 pipeline  


python tools/analysis_tools/browse_dataset.py \    ${CONFIG_FILE} \    [-o, --out-dir ${OUTPUT_DIR}] \    [-p, --phase ${DATASET_PHASE}] \    [-n, --show-number ${NUMBER_IMAGES_DISPLAY}] \    [-i, --show-interval ${SHOW_INTERRVAL}] \    [-m, --mode ${DISPLAY_MODE}] \    [--cfg-options ${CFG_OPTIONS}]


所有参数的说明:


  • config:模型配置文件的路径。

  • -o, --out-dir: 保存图片文件夹,如果没有指定,默认为 './output'。

  • -p, --phase: 可视化数据集的阶段,只能为 ['train', 'val', 'test'] 之一,默认为 'train'。

  • -n, --show-number: 可视化样本数量。如果没有指定,默认展示数据集的所有图片。

  • -m, --mode: 可视化的模式,只能为 ['original', 'transformed', 'pipeline'] 之一。默认为 'transformed'。

  • --cfg-options : 对配置文件的修改,参考学习配置文件。

学习配置文件链接:https://mmyolo.readthedocs.io/zh-cn/latest/tutorials/config.html


`-m, --mode` 用于设置可视化的模式,默认设置为 'transformed'。- 如果 `--mode` 设置为 'original',则获取原始图片;- 如果 `--mode` 设置为 'transformed',则获取预处理后的图片;- 如果 `--mode` 设置为 'pipeline',则获得数据流水线所有中间过程图片。

更多内容可参考可视化数据集文档:

https://mmyolo.readthedocs.io/zh-cn/latest/useful_tools/browse_dataset.html


例如:


python tools/analysis_tools/browse_dataset.py cor data_analyse --show-number 10 --mode 'pipeline'--out-dir

(图片比较大 number 为 1 就可以)


检查优化器配置


python tools/analysis_tools/vis_scheduler.py configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py --dataset-size 1000 --ngpus 1 --out-dir data_analyse


更多内容可参考可视化优化器参数策略文档:

https://mmyolo.readthedocs.io/zh-cn/latest/useful_tools/vis_scheduler.html



打印全部配置文件


获得全部配置文件可以通过 mim 脚本获得:


mim runmim run mmdet print_config     configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py  --save-path configs_full/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py


也可以在开始训练后的输出路径中获得(默认为 work_dir/ 配置文件名/配置文件 .py)。


在总配置文件中,首先检查类别信息、json 文件和图片路径。这是能否跑通的基础。


2.1.5 训练



可视化:


在我们刚刚新建的 config 文件 configs/custom_dataset/yolov5_s-v61_syncbn_fast_1xb32-100e_cat.py 中添加 tensorboard 配置(写在最后一行即可):


visualizer = dict(vis_backends=[dict(type='LocalVisBackend'),dict(type='TensorboardVisBackend')])


训练:


python tools/train.py configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py


如果训练中途停止,可以在训练命令最后加上 --resume,程序会自动从 work_dirs 中加载最新的权重文件恢复训练。


python tools/train.py configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py --resume


上述配置大概需要 3.0G 显存,如果你的显存不够,可以考虑开启混合精度训练。


python tools/train.py configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py --amp



运行训练命令后,Tensorboard 文件会生成在可视化文件夹 work_dirs/yolov5_s-v61_syncbn_fast_1xb32-100e_cat/${TIMESTAMP}/vis_data 下, 运行下面的命令便可以在网页链接使用 Tensorboard 查看 loss、学习率和 coco/bbox_mAP 等可视化数据了:


tensorboard --logdir=work_dirs/yolov5_s-v61_fast_1xb12-40e_cat/20230823_171741


注意:检查l ogdir 路径是不是最新的。


在本人运行中发现,使用 tensorboard 可能会遇到以下报错:


MMYOLO 安装并不会默认安装 tensorboard。所以未安装 tensorbord 就使用上述命令,可能会报 chardet 相关错误。所以第一次使用可能需要先运行一下命令,然后安装 tensorboard。


pip install chardet


如果运行中遇到问题:module 'distutils' has no attribute 'version' ,解决方法可以参考:https://zhuanlan.zhihu.com/p/556704117


2.1.6 测试



训练中 MMYOLO 会按照指定的间隔运行测试,打印测试指标和结果。我们在训练完成后,可以通过以下命令测试得到的模型的表现:


python tools/test.py configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py   work_dirs/yolov5_s-v61_fast_1xb12-40e_cat/epoch_40.pth    --show-dir show_results


如果想输出每个分类的指标(当然对于单一类别,本步骤没有多大意义,但对于多类别目标识别还是很有意义的),附加参数:


--cfg-options test_evaluator.classwise=True



2.1.7 可视化



查看网络结构:


python demo/featmap_vis_demo.py  data/cat/images/IMG_20210705_084125__01.jpg  configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py        work_dirs/yolov5_s-v61_fast_1xb12-40e_cat/epoch_40.pth   --preview-model


可以在命令最后加上 > net.txt 将结果存入 net.txt 中(也可以用 2.1.8 模型复杂度分析脚本,也能打印出网络结构,不全面,但很清晰)


画出特征图:


python demo/featmap_vis_demo.py data/cat/images/IMG_20221020_112705.jpg             configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py      work_dirs/yolov5_s-v61_fast_1xb12-40e_cat/epoch_40.pth     --target-layers backbone    --channel-reduction squeeze_mean


python demo/featmap_vis_demo.py  data/cat/images/IMG_20210627_225110.jpg          configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py      work_dirs/yolov5_s-v61_fast_1xb12-40e_cat/epoch_40.pth     --target-layers neck.upsample_layers[0]    --channel-reduction squeeze_mean


具体参数参考:

https://mmyolo.readthedocs.io/zh-cn/latest/get_started/15_minutes_object_detection.html


2.1.8 模型复杂度分析



python tools/analysis_tools/get_flops.py configs/yolov5/yolov5_s-v61_fast_1xb12-40e_cat.py


默认打印:总体的 Input shape:  Model Flops:   Model Parameters:。以及网络层次每层情况

使用 --not-show-table 不显示每层情况


其他参数类似,见:

https://mmyolo.readthedocs.io/zh-cn/latest/recommended_topics/complexity_analysis.html


2.2 多类别


2.2.1 多类别数据下载与整理



上面讲了单一类别目标识别任务的相关数据准备和训练的说明。下面对多类别数据进行补充。在数据获取方面可以是自制数据集也可以是 MMYOLO 配套的示例数据集,这里以 COCO 数据集为例。


下载:


wget -P data https://extremevision-js-userfile.oss-cn-hangzhou.aliyuncs.com/user-25117-files/ff6429ed-0f22-4759-aa1e-f3d3f8dc4b40/coco.zip



结构:




train2017 val2017 下均为图片,两个 json 是图片信息和标注信息。


检查:


python tools/analysis_tools/browse_coco_json.py \    --img-dir data/COCO128/coco/train2017 \    --ann-file data/COCO128/coco/annotations/instances_train2017.json


运行时会给出图片信息、类别信息:如种类数目、名称等。但是在复用时,不需要。


2.2.2 配置文件的复用更改



首先,改数据文件路径:


# ======================= Possible modified parameters =======================# -----data changes-----# -----data related-----data_root = 'data/COCO128/coco/'  # Root path of data# Path of train annotation filetrain_ann_file = 'data/COCO128/coco/annotations/instances_train2017.json'train_data_prefix = 'train2017/'  # Prefix of train image path# Path of val annotation fileval_ann_file = 'data/COCO128/coco/annotations/instances_val2017.json'val_data_prefix = 'val2017/'  # Prefix of val image path
num_classes = 80  # Number of classes for classification# Batch size of a single GPU during trainingtrain_batch_size_per_gpu = 4# Worker to pre-fetch data for each single GPU during trainingtrain_num_workers = 4# persistent_workers must be False if num_workers is 0persistent_workers = True
# -----train val related-----# Base learning rate for optim_wrapperbase_lr = 0.01max_epochs = 4  # Maximum training epochsnum_last_epochs = 15  # Last epoch number to switch training pipeline
# ======================= Possible modified parameters =======================# -----data related-----img_scale = (640, 640)  # width, height# Dataset type, this will be used to define the datasetdataset_type = 'YOLOv5CocoDataset'# Batch size of a single GPU during validationval_batch_size_per_gpu = 1# Worker to pre-fetch data for each single GPU during validationval_num_workers = 2


注意:开始的超参数修改并不会起作用。要在后面的 dict 中调用才可以。(继承后不会修改父文件超参数部分,只会修改 dict 中部分)。所以 要改 train_dataloader、val_dataloader、test_dataloadertest_evaluator 、val_evaluator、default_hooks 等用到所更改的超参数的部分。


而后,改类别:


类别名称改法:


METAINFO = {    'classes':    ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train',     'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign',     'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep',     'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella',     'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',     'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard',     'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork',     'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange',     'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair',     'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv',     'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave',     'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase',     'scissors', 'teddy bear', 'hair drier', 'toothbrush'),    # palette is a list of color tuples, which is used for visualization.    'palette':    [(220, 20, 60), (119, 11, 32), (0, 0, 142), (0, 0, 230), (106, 0, 228),     (0, 60, 100), (0, 80, 100), (0, 0, 70), (0, 0, 192), (250, 170, 30),     (100, 170, 30), (220, 220, 0), (175, 116, 175), (250, 0, 30),     (165, 42, 42), (255, 77, 255), (0, 226, 252), (182, 182, 255),     (0, 82, 0), (120, 166, 157), (110, 76, 0), (174, 57, 255),     (199, 100, 0), (72, 0, 118), (255, 179, 240), (0, 125, 92),     (209, 0, 151), (188, 208, 182), (0, 220, 176), (255, 99, 164),     (92, 0, 73), (133, 129, 255), (78, 180, 255), (0, 228, 0),     (174, 255, 243), (45, 89, 255), (134, 134, 103), (145, 148, 174),     (255, 208, 186), (197, 226, 255), (171, 134, 1), (109, 63, 54),     (207, 138, 255), (151, 0, 95), (9, 80, 61), (84, 105, 51),     (74, 65, 105), (166, 196, 102), (208, 195, 210), (255, 109, 65),     (0, 143, 149), (179, 0, 194), (209, 99, 106), (5, 121, 0),     (227, 255, 205), (147, 186, 208), (153, 69, 1), (3, 95, 161),     (163, 255, 0), (119, 0, 170), (0, 182, 199), (0, 165, 120),     (183, 130, 88), (95, 32, 0), (130, 114, 135), (110, 129, 133),     (166, 74, 118), (219, 142, 185), (79, 210, 114), (178, 90, 62),     (65, 70, 15), (127, 167, 115), (59, 105, 106), (142, 108, 45),     (196, 172, 0), (95, 54, 80), (128, 76, 255), (201, 57, 1),     (246, 0, 122), (191, 162, 208)]}


这是 MMDetection 中 coco 数据类的定义,更改方法:


声明超参数


metainfo = dict(classes=('','', ....), palette=[(20, 220, 60),( , , ), ....])

在 dataloader 中调用(train_dataloader、val_dataloader、test_dataloader等)


val_dataloader = dict(    dataset=dict(        metainfo=metainfo        ))


类别个数改法:


num_classes = len(class_name)


model = dict(   ...    bbox_head=dict(            head_module=dict(        num_classes=num_classes                       ),        ) .. )



3. 更改网络-基本


3.1 更改 backbone


3.1.1 更改 MMYOLO 中的其他 backbone



假设想将 YOLOv6EfficientRep  作为 YOLOv5 的主干网络,则配置文件如下:


_base_ = './yolov5_s-v61_syncbn_8xb16-300e_coco.py'model = dict(    backbone=dict(    type='YOLOv6EfficientRep',    norm_cfg=dict(type='BN', momentum=0.03,eps=0.001),    act_cfg=dict(type='ReLU', inplace=True)))


tpye 和参数,看 MMYOLO/models/backbones/__init__.py 和 MMYOLO/models/backbones/ 中对应 backbone 实现 py 文件的类的参数(写在备注或 init 函数的参数中)。


3.1.2 更换 MMDetection 中的 backbone



使用 MMDetection 里 resnet50:


_base_ = './yolov5_s-v61_syncbn_8xb16-300e_coco.py'deepen_factor = _base_.deepen_factorwiden_factor = 1.0channels = [512, 1024, 2048]model = dict(backbone=dict(_delete_=True, # 将 _base_ 中关于 backbone 的字段删除type='mmdet.ResNet', # 使用 mmdet 中的 ResNetdepth=50,num_stages=4,out_indices=(1, 2, 3),frozen_stages=1,norm_cfg=dict(type='BN', requires_grad=True),norm_eval=True,style='pytorch',init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')),neck=dict(type='YOLOv5PAFPN',widen_factor=widen_factor,in_channels=channels, # 注意:ResNet-50 输出的3个通道是 [512, 1024, 2048],和原先的 yolov5-s neck 不匹配,需要更改out_channels=channels),bbox_head=dict(    type='YOLOv5Head',    head_module=dict(type='YOLOv5HeadModule',        in_channels=channels, # head 部分输入通道也要做相应更改        widen_factor=widen_factor)))


改法:


  • _delete_要有,删除原来的所有配置

  • 参数参照 MMDetection 里 model 的 backbone 实现 py 文件,一般注意 out_indices 参数

  • neck 和 head 的输入/输出 channel 要改


>>> from mmdet.models import ResNet>>> import torch>>> self = ResNet(depth=18,out_indices=(1, 2, 3) #这一行,尽量所有参数和配置文件一样>>> self.eval()>>> inputs = torch.rand(1, 3, 32, 32)>>> level_outputs = self.forward(inputs)>>> for level_out in level_outputs:...    print(tuple(level_out.shape))


获得的第二个数字为各个输出通道的维度,写做[ ,  ,  ]


  • widen_factor 改为 1, 因为 out_channels 由 widen_factor 控制, 的out_channels = out_channels * widen_factor


使用 MMDetection 里 regnet:



channels = [192, 432, 1008]
model = dict(    backbone=dict(        _delete_=True,        type='mmdet.RegNet',              arch=dict(            w0=88,            wa=26.31,            wm=2.25,            group_w=48,            depth=25,            bot_mul=1.0),        out_indices=(1, 2, 3),        init_cfg=dict(            type='Pretrained', checkpoint='down_model/regnetx-400mf_8xb128_in1k_20211213-89bfc226.pth'        )    ),


  • 根据 MMDetection 里 reg 实现,取了 arch 参数

  • 根据 yolo 选择了 out_indices 参数

  • 根据测试脚本,得到输出尺度

from mmdet.models import RegNetimport torch
self = RegNet(    arch=dict(        w0=88,        wa=26.31,        wm=2.25,        group_w=48,        depth=25,        bot_mul=1.0),    out_indices=(1, 2, 3), )self.eval()inputs = torch.rand(1, 3, 32, 32)level_outputs = self.forward(inputs)for level_out in level_outputs:    print(tuple(level_out.shape))  # [192, 432, 1008]


  • 权重来源:

https://mmpretrain.readthedocs.io/zh_CN/latest/papers/regnet.html

  • 模型库统计:

https://mmpretrain.readthedocs.io/zh_CN/latest/modelzoo_statistics.html


3.1.3 更改 MMPretrain 里的 backbone



需要先安装 MMPretrain,最后使用软链接将 mmpretrain/mmpretrain 链接到 MMYOLO/mmpretrain 方便跳转查看。

安装方法参考:https://mmpretrain.readthedocs.io/zh-cn/latest/get_started.html#id2



custom_imports = dict(imports=['mmpretrain.models'], allow_failed_imports=False)# 注册mmpretrainmax_epochs = 50train_batch_size_per_gpu = 4train_num_workers = 4widen_factor: float = 1.0# load_from = 'https://download.openmmlab.com/MMYOLO/v0/yolov5/yolov5_s-v61_syncbn_fast_8xb16-300e_coco/yolov5_s-v61_syncbn_fast_8xb16-300e_coco_20220918_084700-86e02187.pth'  # noqa
channels = [192, 384, 768]
model = dict(    backbone=dict(        _delete_=True,        type='mmpretrain.SwinTransformer',        arch='tiny',        img_size=224,        patch_size=4,        in_channels=3,        window_size=7,        drop_rate=0.,        drop_path_rate=0.1,        out_indices=(1, 2, 3),        out_after_downsample=False,        use_abs_pos_embed=False,        interpolate_mode='bicubic',        with_cp=False,        frozen_stages=-1,        norm_eval=False,        pad_small_map=False,        norm_cfg=dict(type='LN'),        stage_cfgs=dict(),        patch_cfg=dict(),        init_cfg=dict(            type='Pretrained',            checkpoint='down_model/swin_tiny_224_b16x64_300e_imagenet_20210616_090925-66df6be6.pth',            prefix='backbone.'        )    ),


更改方法与使用 MMDetection 里的类似。注意要注册 MMPretrain 以及 inin_cfg 中 prefix 参数。


在使用脚本测试 backbone 输出时,有的 backbone 输出不满足 [(1,x,y,z),(1,x2,y2,z2),(1,x3,y3,z3)] 形式,yolov5 的 neck 对不上,这样的 backbone 不能直接用于 yolov5 的替换。


预训练权重:

https://mmpretrain.readthedocs.io/zh_CN/latest/modelzoo_statistics.html


3.2 backbone 加插件


model = dict(backbone=dict(plugins=[    dict(    cfg=dict(    type='GeneralizedAttention',spatial_range=-1,    num_heads=8,attention_type='0011',kv_stride=2),    stages=(False, False, True, True))        ]))


可以使用 2.1.7 中的命令查看网络结构。


3.3 更改 head


head 部分成分比较多。每个都可以按 backbone、neck 思路改。包括:


  • head_module

  • prior_generator

  • loss类

    loss_cls

    loss_obj

    loss_bbox


# 一个head例:bbox_head=dict(    type='YOLOv5Head',    head_module=dict(        type='YOLOv5HeadModule',        num_classes=num_classes,        in_channels=[256, 512, 1024],        widen_factor=widen_factor,        featmap_strides=strides,        num_base_priors=3),    prior_generator=dict(        type='mmdet.YOLOAnchorGenerator',        base_sizes=anchors,        strides=strides),    # scaled based on number of detection layers    loss_cls=dict(        type='mmdet.CrossEntropyLoss',        use_sigmoid=True,        reduction='mean',        loss_weight=loss_cls_weight *        (num_classes / 80 * 3 / num_det_layers)),    loss_bbox=dict(        type='IoULoss',        iou_mode='ciou',        bbox_format='xywh',        eps=1e-7,        reduction='mean',        loss_weight=loss_bbox_weight * (3 / num_det_layers),        return_iou=True),    loss_obj=dict(        type='mmdet.CrossEntropyLoss',        use_sigmoid=True,        reduction='mean',        loss_weight=loss_obj_weight *        ((img_scale[0] / 640)**2 * 3 / num_det_layers)),


3.3.1 loss 类更改



loss_cls:


loss_cls=dict(    _delete_=True,    type='mmdet.SmoothL1Loss',    beta=0.5,    reduction='sum',    loss_weight=1.0),


替换其他同理。


3.3.2 head_module 更改



       head_module=dict(            type='YOLOv7HeadModule',            num_classes=num_classes,            in_channels=[256, 512, 1024],            featmap_strides=strides,            num_base_priors=3)



总结


本文综合网络上多处 MMYOLO 文档和个人使用经验,包括从安装到训练再到简单的模型网络修改方法,希望给大家带来帮助。


仅需一块3090显卡,高效部署InternLM-20B模型

2023-11-08

OpenAI首届开发者大会,短短45分钟,如何再次让AI圈一夜未眠

2023-11-07

20天从新手到技术写作大咖!OpenMMLab第3期写作训练营开课啦!

2023-11-03


点击下方“阅读原文”直达 MMYOLO,欢迎使用

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存