MMDetection系列 | 3. MMDetection自定义模型训练

简介: MMDetection系列 | 3. MMDetection自定义模型训练

1. 设计Backbone


创建一个新的py文件,这里我的文件名是spinmlp.py,将其放在 mmdet/models/backbones/ 的路径下,也就是 mmdet/models/backbones/spinmlp.py 。


import torch.nn as nn
......
from ..builder import BACKBONES
@BACKBONES.register_module()
class SpinMLP(nn.Module):
    def __init__(self, patch_size, in_c, hidden_dim, expansion_factor, num_blocks, num_classes=80,
                 weightattn=True, Backbone=True):
        super().__init__()
        self.num_blocks = num_blocks
        # self.token_dim = (image_size[0] // patch_size[0]) * (image_size[1] // patch_size[1])
        self.patch_embed = nn.Conv2d(in_c, hidden_dim, kernel_size=patch_size, stride=patch_size)
        self.stages = nn.Sequential(
            *[nn.Sequential(
                SpinMLPBlock(hidden_dim, expansion_factor, weightattn)
            ) for i in range(self.num_blocks)]
        )
        # 作为backbone,这里不需要为期添加一个head,只需要作为特征即可
        self.head = nn.Linear(hidden_dim, num_classes) if Backbone is False else None
        self._init_weights()
  ......


2. 导入模块


这一步很重要。


基于刚刚设计好的backbone模块,这里将一下行添加到 mmdet/models/backbones/__init__.py


from .spinmlp import SpinMLP


同时,在__all__中添加backbone的名称,如下所示:

image.png


还有一个添加配置的方法是:


custom_imports = dict(
    imports=[
        'mmdet.models.backbones.spinmlp',
    ],
    allow_failed_imports=False)


但是,这种方法我尝试过是配置无效的。


3. 配置文件


在MMDetection中我们知道,各种文件都是通过配置来进行构建。由于我使用了新的数据集,也替换了新的网路结构,所以我新建了一个新的配置文件,名称为:detr_spinmlp_8x8_150e_mask.py


将原本是resnet的替换为我设计的spinmlp结构:


# model settings
model = dict(
    type='DETR',
    backbone=dict(
        type='SpinMLP',
        patch_size=(16, 16),  # [1, 2048, 28, 28]
        in_c=3,
        hidden_dim=1024,
        expansion_factor=4,
        num_blocks=4,
        num_classes=80,
        weightattn=True,
        Backbone=True),


4. 模型训练


根据官方的文档资料的自定义模型部分:https://mmdetection.readthedocs.io/en/latest/tutorials/customize_models.html


基于以上如此操作之后,应该就能直接在命令行中运行了,但是在我这里报了一个错误:


KeyError: ‘SpinMLP is not in the models registry’


详细如下所示:

image.png


注意,这里的错误是我在命令行运行时所报的错误,随后我尝试在Pycharm进行运行(需要更改工作目录和config参数),神奇的在Pycharm可以正常的训练与验证。那么,这就说明其实我的配置是正确的。


为了寻找到在终端不能运行,而在Pycharm中可以运行的原因,我查看了下网上的相关资料,并没有找到合适的解决方法。随后,在MMDetection中找到的一个和我问题一一的issue:import custom model error


后来我找到了解决的方案。我们可以用mmdet中已有的backbone进行训练,是因为这些backbone本身已经被registry,而我们自定义的backbone,需要重新的registry。

image.png


随后,我重新pip之后,在命令行输入指令,即可成功。


终端训练:

image.png


Pycharm训练:

image.png


支持,自定义模型训练圆满成功。


ps:有时候不仅仅是自定义的模型,还有一些内置的模型可能也会出现 'xxx is not in the models registry' 的问题,一方面可能是mmdet的版本有问题,可以尝试换一个版本;另外一个原因就是配置有问题。


而且,这里再补充一个我训练时候觉得很不对劲的bug。我的服务器使用的是4张3090,我设置1卡跑的时候,0卡还是存在2-3g的占用,如下所示:

image.png


所以,进行实验的时候需要0卡空余一点空间,才可以正常运行,否则同样会出现OOM的问题。


5. 完整配置


这里附上我使用自定义的模型,使用detr的训练方法,进行口罩数据集的检测的完整配置文件:


  • detr_spinmlp_8x2_150e_mask.py
_base_ = [
    '../_base_/default_runtime.py'
]
# custom_imports = dict(
#     imports=[
#         'mmdet.models.backbones.spinmlp.py',
#     ],
#     allow_failed_imports=False)
# model settings
model = dict(
    type='DETR',
    backbone=dict(
        type='SpinMLP',
        patch_size=(16, 16),  # [1, 2048, 28, 28]
        in_c=3,
        hidden_dim=2048,
        expansion_factor=4,
        num_blocks=4,
        num_classes=80,
        weightattn=True,
        Backbone=True),
    bbox_head=dict(
        type='DETRHead',
        num_classes=3,      # 类别设置
        in_channels=2048,
        transformer=dict(
            type='Transformer',
            encoder=dict(
                type='DetrTransformerEncoder',
                num_layers=6,
                transformerlayers=dict(
                    type='BaseTransformerLayer',            # 同样继承自mmcv
                    attn_cfgs=[
                        dict(
                            type='MultiheadAttention',      # MultiheadAttention继承自mmcv
                            embed_dims=256,
                            num_heads=8,
                            dropout=0.1)
                    ],
                    feedforward_channels=2048,
                    ffn_dropout=0.1,
                    operation_order=('self_attn', 'norm', 'ffn', 'norm'))),
            decoder=dict(
                type='DetrTransformerDecoder',
                return_intermediate=True,
                num_layers=6,
                transformerlayers=dict(
                    type='DetrTransformerDecoderLayer',
                    attn_cfgs=dict(
                        type='MultiheadAttention',
                        embed_dims=256,
                        num_heads=8,
                        dropout=0.1),
                    feedforward_channels=2048,
                    ffn_dropout=0.1,
                    operation_order=('self_attn', 'norm', 'cross_attn', 'norm',
                                     'ffn', 'norm')),
            )),
        positional_encoding=dict(
            type='SinePositionalEncoding', num_feats=128, normalize=True),
        loss_cls=dict(
            type='CrossEntropyLoss',
            bg_cls_weight=0.1,
            use_sigmoid=False,
            loss_weight=1.0,
            class_weight=1.0),
        loss_bbox=dict(type='L1Loss', loss_weight=5.0),
        loss_iou=dict(type='GIoULoss', loss_weight=2.0)),
    # training and testing settings
    train_cfg=dict(
        assigner=dict(
            type='HungarianAssigner',
            cls_cost=dict(type='ClassificationCost', weight=1.),
            reg_cost=dict(type='BBoxL1Cost', weight=5.0, box_format='xywh'),
            iou_cost=dict(type='IoUCost', iou_mode='giou', weight=2.0))),
    test_cfg=dict(max_per_img=100))
# dataset settings
dataset_type = 'CocoDataset'
data_root = 'data/mask/'
classes = ('with_mask', 'without_mask', 'mask_weared_incorrect')
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
# train_pipeline, NOTE the img_scale and the Pad's size_divisor is different
# from the default setting in mmdet.
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations', with_bbox=True),
    dict(type='RandomFlip', flip_ratio=0.5),
    dict(type='Resize', img_scale=(480, 480), multiscale_mode='value', ratio_range=None),   # 需要设置为宽高等长
    dict(type='Normalize', **img_norm_cfg),
    dict(type='Pad', pad_to_square=True),       # The size and size_divisor must be None when pad2square is True
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
]
# test_pipeline, NOTE the Pad's size_divisor is different from the default
# setting (size_divisor=32). While there is little effect on the performance
# whether we use the default setting or use size_divisor=1.
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(480, 480),     # 需要设置为宽高等长
        flip=False,
        transforms=[
            dict(type='Resize', multiscale_mode='value', ratio_range=None),
            dict(type='RandomFlip'),
            dict(type='Normalize', **img_norm_cfg),
            dict(type='Pad', pad_to_square=True),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img'])
        ])
]
data = dict(
    samples_per_gpu=2,
    workers_per_gpu=1,
    train=dict(
        type=dataset_type,
        classes=classes,
        ann_file=data_root + 'annotations/train.json',    # 训练集标注文件存放路径
        img_prefix=data_root + 'train/',       # 训练集图像存放路径
        pipeline=train_pipeline),
    val=dict(
        type=dataset_type,
        classes=classes,
        ann_file=data_root + 'annotations/val.json',
        img_prefix=data_root + 'val/',
        pipeline=test_pipeline),
    test=dict(
        type=dataset_type,
        classes=classes,
        ann_file=data_root + 'annotations/val.json',
        img_prefix=data_root + 'val/',
        pipeline=test_pipeline))
# optimizer setting
optimizer = dict(
    type='AdamW',
    lr=0.0001,
    weight_decay=0.0001,
    paramwise_cfg=dict(
        custom_keys={'backbone': dict(lr_mult=0.1, decay_mult=1.0)}))
# config setting
evaluation = dict(interval=5, metric='bbox')   # 5个epoch验证一次
optimizer_config = dict(grad_clip=dict(max_norm=0.1, norm_type=2))
checkpoint_config = dict(interval=20)          # 20个epoch保存一次权重
log_config = dict(interval=20, hooks=[dict(type='TextLoggerHook')])
# learning policy
lr_config = dict(policy='step', step=[100])
runner = dict(type='EpochBasedRunner', max_epochs=10)
目录
相关文章
|
3天前
|
机器学习/深度学习 数据采集 人工智能
人工智能:构建自定义机器学习模型的步骤与技巧
【6月更文挑战第25天】构建自定义机器学习模型涉及明确问题、数据收集预处理、特征工程、模型选择训练、评估优化及部署监控。关键技巧包括选择适配的算法、重视数据预处理、精巧的特征工程、有效评估优化和适时的模型更新。通过这些步骤和技巧,可提升模型性能与泛化能力。
|
1月前
|
机器学习/深度学习 算法 数据处理
构建自定义机器学习模型:Scikit-learn的高级应用
【4月更文挑战第17天】本文探讨了如何利用Scikit-learn构建自定义机器学习模型,包括创建自定义估计器、使用管道集成数据处理和模型、深化特征工程以及调优与评估模型。通过继承`BaseEstimator`和相关Mixin类,用户可实现自定义算法。管道允许串联多个步骤,而特征工程涉及多项式特征和自定义变换。模型调优可借助交叉验证和参数搜索工具。掌握这些高级技巧能提升机器学习项目的效果和效率。
|
机器学习/深度学习 TensorFlow API
构建自定义机器学习模型:TensorFlow的高级用法
在机器学习领域,TensorFlow已经成为最受欢迎和广泛使用的开源框架之一。它提供了丰富的功能和灵活性,使开发者能够构建各种复杂的机器学习模型。在本文中,我们将深入探讨TensorFlow的高级用法,重点介绍如何构建自定义机器学习模型。
181 0
|
机器学习/深度学习 自然语言处理 算法
SnowNLP使用自定义语料进行模型训练(情感分析)
SnowNLP使用自定义语料进行模型训练(情感分析)
1407 1
SnowNLP使用自定义语料进行模型训练(情感分析)
|
机器学习/深度学习 SQL 人工智能
如何在 PAI-Studio 上传自定义算法|学习笔记
快速学习如何在 PAI-Studio 上传自定义算法。
101 0
如何在 PAI-Studio 上传自定义算法|学习笔记
|
机器学习/深度学习 人工智能 文字识别
【人工智能】机器学习及与智能数据处理之降维算法PCA及其应用手写字体识别以及【自定义数据集】
利用PCA算法实现手写字体识别,要求: 1、实现手写数字数据集的降维; 2、比较两个模型(64维和10维)的准确率; 3、对两个模型分别进行10次10折交叉验证,绘制评分对比曲线。
412 1
【人工智能】机器学习及与智能数据处理之降维算法PCA及其应用手写字体识别以及【自定义数据集】
|
JSON 算法 API
阿里云PAI EAS 自定义Token使用示例
为实现一站式算法应用,PAI针对在线推理场景提供了在线预测服务PAI-EAS(Elastic Algorithm Service),支持基于异构硬件(CPU和GPU)的模型加载和数据请求的实时响应。通过PAI-EAS,您可以将模型快速部署为RESTful API,再通过HTTP请求的方式调用该服务。模型部署后,可以基于http方式&认证Token的方式实现服务的Restful 方式调用。本文主要演示自定义token模型的部署方式。
2332 2
阿里云PAI EAS 自定义Token使用示例
|
机器学习/深度学习 存储 Java
阿里云机器学习模型在线服务自定义Processor部署PMML模型(二)
阿里云机器学习模型在线服务自定义Processor部署PMML模型(一)中介绍了使用EASCMD搭建环境,进行自定义processor的部署,这里介绍使用阿里云提供的镜像进行模型的在线部署,并通过Java SDK演示模型的在线调用。
3246 2
阿里云机器学习模型在线服务自定义Processor部署PMML模型(二)
|
机器学习/深度学习 弹性计算 Ubuntu
阿里云机器学习模型在线服务自定义Processor部署PMML模型(一)
Processor是包含在线预测逻辑(模型加载和请求预测逻辑)的程序包,如果PAI-EAS提供的官方通用Processor无法满足模型部署需求,则可以根据Processor的开发标准自定义Processor。本文演示如果在本地搭建环境进行测试,并通过EASCMD指令打包方式上传服务到EAS服务器,实现模型在线调用。
128386 0
阿里云机器学习模型在线服务自定义Processor部署PMML模型(一)
|
SQL 人工智能 分布式计算
【教程】5分钟在PAI算法市场发布自定义算法
概述 在人工智能领域存在这样的现象,很多用户有人工智能的需求,但是没有相关的技术能力。另外有一些人工智能专家空有一身武艺,但是找不到需求方。这意味着在需求和技术之间需要一种连接作为纽带。 今天PAI正式对外发布了“AI市场”以及“PAI自定义算法”两大功能,可以帮助用户5分钟将线下的spark算法或是pyspark算法发布成算法组件,并且支持组件发布到AI市场供更多用户使用。
10140 1