.YOLO-Worldconfigssegmentationyolo_world_seg_l_dual_vlpan_2e-4_80e_8gpus_seghead_finetune_lvis.py
代码语言:javascript
复制_base_ = (
'../../third_party/mmyolo/configs/yolov8/yolov8_l_mask-refine_syncbn_fast_8xb16-500e_coco.py'
)
# 定义基础配置文件路径
custom_imports = dict(imports=['yolo_world'], allow_failed_imports=False)
# 自定义导入模块,禁止导入失败
# 超参数设置
num_classes = 1203
num_training_classes = 80
max_epochs = 80 # 最大训练轮数
close_mosaic_epochs = 10
save_epoch_intervals = 5
text_channels = 512
neck_embed_channels = [128, 256, _base_.last_stage_out_channels // 2]
neck_num_heads = [4, 8, _base_.last_stage_out_channels // 2 // 32]
base_lr = 2e-4
weight_decay = 0.05
train_batch_size_per_gpu = 8
load_from = 'pretrained_models/yolo_world_l_clip_base_dual_vlpan_2e-3adamw_32xb16_100e_o365_goldg_train_pretrained-0e566235.pth'
persistent_workers = False
# Polygon2Mask 参数设置
downsample_ratio = 4
mask_overlap = False
use_mask2refine = True
max_aspect_ratio = 100
min_area_ratio = 0.01
# 模型设置
model = dict(
type='YOLOWorldDetector',
mm_neck=True,
num_train_classes=num_training_classes,
num_test_classes=num_classes,
data_preprocessor=dict(type='YOLOWDetDataPreprocessor'),
backbone=dict(
_delete_=True,
type='MultiModalYOLOBackbone',
image_model={{_base_.model.backbone}},
frozen_stages=4, # 冻结图像骨干网络的阶段数
text_model=dict(
type='HuggingCLIPLanguageBackbone',
model_name='openai/clip-vit-base-patch32',
frozen_modules=['all'])),
neck=dict(type='YOLOWorldDualPAFPN',
freeze_all=True,
guide_channels=text_channels,
embed_channels=neck_embed_channels,
num_heads=neck_num_heads,
block_cfg=dict(type='MaxSigmoidCSPLayerWithTwoConv'),
text_enhancder=dict(type='ImagePoolingAttentionModule',
embed_channels=256,
num_heads=8)),
# 定义一个字典,包含YOLOWorldSegHead的相关参数
bbox_head=dict(type='YOLOWorldSegHead',
head_module=dict(type='YOLOWorldSegHeadModule',
embed_dims=text_channels,
num_classes=num_training_classes,
mask_channels=32,
proto_channels=256,
freeze_bbox=True),
mask_overlap=mask_overlap,
loss_mask=dict(type='mmdet.CrossEntropyLoss',
use_sigmoid=True,
reduction='none'),
loss_mask_weight=1.0),
# 定义训练配置,包含分配器的参数
train_cfg=dict(assigner=dict(num_classes=num_training_classes)),
# 定义测试配置,包含mask_thr_binary和fast_test参数
test_cfg=dict(mask_thr_binary=0.5, fast_test=True))
# 定义数据预处理流程的前置转换操作,包括加载图像和加载注释
pre_transform = [
dict(type='LoadImageFromFile', backend_args=_base_.backend_args), # 加载图像文件
dict(type='LoadAnnotations',
with_bbox=True,
with_mask=True,
mask2bbox=True) # 加载注释,包括边界框和掩码
]
# 定义数据预处理流程的后置转换操作,包括Albumentations增强、YOLOv5HSV随机增强、随机翻转和多边形转掩码
last_transform = [
dict(type='mmdet.Albu',
transforms=_base_.albu_train_transforms, # 使用Albumentations增强
bbox_params=dict(type='BboxParams',
format='pascal_voc',
label_fields=['gt_bboxes_labels',
'gt_ignore_flags']), # 边界框参数设置
keymap={
'img': 'image',
'gt_bboxes': 'bboxes'
}), # 映射关键字
dict(type='YOLOv5HSVRandomAug'), # YOLOv5HSV随机增强
dict(type='mmdet.RandomFlip', prob=0.5), # 随机翻转
dict(type='Polygon2Mask',
downsample_ratio=downsample_ratio,
mask_overlap=mask_overlap) # 多边形转掩码
]
# 定义文本转换操作,包括随机加载文本和打包检测输入
text_transform = [
dict(type='RandomLoadText',
num_neg_samples=(num_classes, num_classes),
max_num_samples=num_training_classes,
padding_to_max=True,
padding_value=''), # 随机加载文本
dict(type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 'flip',
'flip_direction', 'texts')) # 打包检测输入
]
# 定义马赛克仿射变换操作,包括多模态马赛克、YOLOv5复制粘贴和YOLOv5随机仿射
mosaic_affine_transform = [
dict(type='MultiModalMosaic',
img_scale=_base_.img_scale,
pad_val=114.0,
pre_transform=pre_transform), # 多模态马赛克
dict(type='YOLOv5CopyPaste', prob=_base_.copypaste_prob), # YOLOv5复制粘贴
dict(
type='YOLOv5RandomAffine',
max_rotate_degree=0.0,
max_shear_degree=0.0,
max_aspect_ratio=100.,
scaling_ratio_range=(1 - _base_.affine_scale, 1 _base_.affine_scale),
border=(-_base_.img_scale[0] // 2, -_base_.img_scale[1] // 2),
border_val=(114, 114, 114),
min_area_ratio=_base_.min_area_ratio,
use_mask_refine=True) # YOLOv5随机仿射
]
# 训练流程包括前置转换操作和马赛克仿射变换操作
train_pipeline = [
*pre_transform, *mosaic_affine_transform,
]
# 创建一个字典,指定模型类型为YOLOv5MultiModalMixUp,概率为mixup_prob
dict(type='YOLOv5MultiModalMixUp',
prob=_base_.mixup_prob,
# 将pre_transform和mosaic_affine_transform的元素合并到一个列表中
pre_transform=[*pre_transform, *mosaic_affine_transform]),
# 将last_transform和text_transform的元素合并到一个列表中
*last_transform, *text_transform
# 定义训练管道的第二阶段,包括预处理、YOLOv5KeepRatioResize、LetterResize、YOLOv5RandomAffine等操作
_train_pipeline_stage2 = [
*pre_transform, # 包含预处理操作
dict(type='YOLOv5KeepRatioResize', scale=_base_.img_scale), # YOLOv5KeepRatioResize操作
dict(type='LetterResize', # LetterResize操作
scale=_base_.img_scale, # 图像缩放比例
allow_scale_up=True, # 允许缩放
pad_val=dict(img=114.0)), # 填充值
dict(type='YOLOv5RandomAffine', # YOLOv5RandomAffine操作
max_rotate_degree=0.0, # 最大旋转角度
max_shear_degree=0.0, # 最大剪切角度
scaling_ratio_range=(1 - _base_.affine_scale, 1 _base_.affine_scale), # 缩放比例范围
max_aspect_ratio=_base_.max_aspect_ratio, # 最大长宽比
border_val=(114, 114, 114), # 边界值
min_area_ratio=min_area_ratio, # 最小区域比例
use_mask_refine=use_mask2refine), # 是否使用掩码细化
*last_transform # 包含最后的转换操作
]
# 将_train_pipeline_stage2与text_transform合并为train_pipeline_stage2
train_pipeline_stage2 = [*_train_pipeline_stage2, *text_transform]
# 定义coco_train_dataset,包括数据集类型、数据根目录、注释文件、数据前缀等信息
coco_train_dataset = dict(
_delete_=True, # 删除标记
type='MultiModalDataset', # 多模态数据集类型
dataset=dict(type='YOLOv5LVISV1Dataset', # 数据集类型为YOLOv5LVISV1Dataset
data_root='data/coco', # 数据根目录
ann_file='lvis/lvis_v1_train_base.json', # 注释文件
data_prefix=dict(img=''), # 数据前缀
filter_cfg=dict(filter_empty_gt=True, min_size=32)), # 过滤配置
class_text_path='data/captions/lvis_v1_base_class_captions.json', # 类别文本路径
pipeline=train_pipeline) # 数据处理管道
# 定义train_dataloader,包括持久化工作进程、每个GPU的训练批量大小、数据集、数据集合并函数等信息
train_dataloader = dict(persistent_workers=persistent_workers,
batch_size=train_batch_size_per_gpu,
collate_fn=dict(type='yolow_collate'), # 数据集合并函数类型
dataset=coco_train_dataset) # 数据集
# 定义测试管道,包括加载文本、PackDetInputs等操作
test_pipeline = [
*_base_.test_pipeline[:-1], # 测试管道的前几个操作
dict(type='LoadText'), # 加载文本操作
dict(type='mmdet.PackDetInputs', # PackDetInputs操作
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
'scale_factor', 'pad_param', 'texts')) # 元数据键
]
# 默认的钩子配置,包括参数调度器和检查点
default_hooks = dict(param_scheduler=dict(scheduler_type='linear',
lr_factor=0.01,
max_epochs=max_epochs),
checkpoint=dict(max_keep_ckpts=-1,
save_best=None,
interval=save_epoch_intervals))
# 自定义的钩子配置
custom_hooks = [
dict(type='EMAHook',
ema_type='ExpMomentumEMA',
momentum=0.0001,
update_buffers=True,
strict_load=False,
priority=49),
dict(type='mmdet.PipelineSwitchHook',
switch_epoch=max_epochs - close_mosaic_epochs,
switch_pipeline=train_pipeline_stage2)
]
# 训练配置,包括最大训练周期、验证间隔、动态间隔
train_cfg = dict(max_epochs=max_epochs,
val_interval=5,
dynamic_intervals=[((max_epochs - close_mosaic_epochs),
_base_.val_interval_stage2)])
# 优化器包装器配置,包括优化器类型、学习率、权重衰减
optim_wrapper = dict(optimizer=dict(
_delete_=True,
type='AdamW',
lr=base_lr,
weight_decay=weight_decay,
# 设置每个 GPU 的训练批量大小
batch_size_per_gpu=train_batch_size_per_gpu),
# 针对参数进行配置,设置偏置和归一化的衰减倍数为0
paramwise_cfg=dict(bias_decay_mult=0.0,
norm_decay_mult=0.0,
custom_keys={
# 针对文本模型的学习率倍数设置为0.01
'backbone.text_model':
dict(lr_mult=0.01),
# 针对logit_scale的权重衰减设置为0.0
'logit_scale':
dict(weight_decay=0.0),
# 针对neck的学习率倍数设置为0.0
'neck':
dict(lr_mult=0.0),
# 针对head_module.reg_preds的学习率倍数设置为0.0
'head.head_module.reg_preds':
dict(lr_mult=0.0),
# 针对head_module.cls_preds的学习率倍数设置为0.0
'head.head_module.cls_preds':
dict(lr_mult=0.0),
# 针对head_module.cls_contrasts的学习率倍数设置为0.0
'head.head_module.cls_contrasts':
dict(lr_mult=0.0)
}),
# 设置构造函数为'YOLOWv5OptimizerConstructor'
constructor='YOLOWv5OptimizerConstructor')
# 评估设置
coco_val_dataset = dict(
_delete_=True, # 删除该键值对
type='MultiModalDataset', # 数据集类型为多模态数据集
dataset=dict(type='YOLOv5LVISV1Dataset', # 数据集配置为YOLOv5LVISV1Dataset
data_root='data/coco/', # 数据根目录
test_mode=True, # 测试模式为True
ann_file='lvis/lvis_v1_val.json', # 标注文件路径
data_prefix=dict(img=''), # 数据前缀
batch_shapes_cfg=None), # 批量形状配置为空
class_text_path='data/captions/lvis_v1_class_captions.json', # 类别文本路径
pipeline=test_pipeline) # 测试管道
val_dataloader = dict(dataset=coco_val_dataset) # 验证数据加载器设置为coco_val_dataset
test_dataloader = val_dataloader # 测试数据加载器设置为验证数据加载器
val_evaluator = dict(type='mmdet.LVISMetric', # 评估器类型为mmdet.LVISMetric
ann_file='data/coco/lvis/lvis_v1_val.json', # 标注文件路径
metric=['bbox', 'segm']) # 评估指标为bbox和segm
test_evaluator = val_evaluator # 测试评估器设置为验证评估器
find_unused_parameters = True # 查找未使用的参数为True
.YOLO-Worldconfigssegmentationyolo_world_seg_m_dual_vlpan_2e-4_80e_8gpus_allmodules_finetune_lvis.py
代码语言:javascript
复制_base_ = (
'../../third_party/mmyolo/configs/yolov8/yolov8_m_mask-refine_syncbn_fast_8xb16-500e_coco.py'
)
# 定义基础配置文件路径
custom_imports = dict(imports=['yolo_world'], allow_failed_imports=False)
# 自定义导入模块,禁止导入失败
# 超参数设置
num_classes = 1203
num_training_classes = 80
max_epochs = 80 # 最大训练周期数
close_mosaic_epochs = 10
save_epoch_intervals = 5
text_channels = 512
neck_embed_channels = [128, 256, _base_.last_stage_out_channels // 2]
neck_num_heads = [4, 8, _base_.last_stage_out_channels // 2 // 32]
base_lr = 2e-4
weight_decay = 0.05
train_batch_size_per_gpu = 8
load_from = 'pretrained_models/yolo_world_m_clip_base_dual_vlpan_2e-3adamw_32xb16_100e_o365_goldg_train_pretrained-2b7bd1be.pth'
persistent_workers = False
# Polygon2Mask
downsample_ratio = 4
mask_overlap = False
use_mask2refine = True
max_aspect_ratio = 100
min_area_ratio = 0.01
# 模型设置
model = dict(
type='YOLOWorldDetector',
mm_neck=True,
num_train_classes=num_training_classes,
num_test_classes=num_classes,
data_preprocessor=dict(type='YOLOWDetDataPreprocessor'),
backbone=dict(
_delete_=True,
type='MultiModalYOLOBackbone',
image_model={{_base_.model.backbone}},
text_model=dict(
type='HuggingCLIPLanguageBackbone',
model_name='openai/clip-vit-base-patch32',
frozen_modules=[])),
neck=dict(type='YOLOWorldDualPAFPN',
guide_channels=text_channels,
embed_channels=neck_embed_channels,
num_heads=neck_num_heads,
block_cfg=dict(type='MaxSigmoidCSPLayerWithTwoConv'),
text_enhancder=dict(type='ImagePoolingAttentionModule',
embed_channels=256,
num_heads=8)),
# 定义 YOLO 网络的头部结构,包括类型、模块类型、嵌入维度、类别数量、掩模通道数和原型通道数
bbox_head=dict(type='YOLOWorldSegHead',
head_module=dict(type='YOLOWorldSegHeadModule',
embed_dims=text_channels,
num_classes=num_training_classes,
mask_channels=32,
proto_channels=256),
mask_overlap=mask_overlap,
# 定义掩模损失函数,使用交叉熵损失,采用 sigmoid 函数,不进行降维
loss_mask=dict(type='mmdet.CrossEntropyLoss',
use_sigmoid=True,
reduction='none'),
# 定义掩模损失的权重
loss_mask_weight=1.0),
# 定义训练配置,包括分配器和类别数量
train_cfg=dict(assigner=dict(num_classes=num_training_classes)),
# 定义测试配置,包括二值化掩模阈值和快速测试标志
test_cfg=dict(mask_thr_binary=0.5, fast_test=True))
# 定义数据预处理的步骤列表,用于数据增强
pre_transform = [
# 从文件加载图像
dict(type='LoadImageFromFile', backend_args=_base_.backend_args),
# 从文件加载标注信息,包括边界框和掩码
dict(type='LoadAnnotations',
with_bbox=True,
with_mask=True,
mask2bbox=True)
]
# 定义最后的数据转换步骤列表
last_transform = [
# 使用 mmdet 库中的 Albu 进行数据增强
dict(type='mmdet.Albu',
transforms=_base_.albu_train_transforms,
bbox_params=dict(type='BboxParams',
format='pascal_voc',
label_fields=['gt_bboxes_labels',
'gt_ignore_flags']),
keymap={
'img': 'image',
'gt_bboxes': 'bboxes'
}),
# 使用 YOLOv5HSVRandomAug 进行数据增强
dict(type='YOLOv5HSVRandomAug'),
# 随机翻转图像
dict(type='mmdet.RandomFlip', prob=0.5),
# 将多边形转换为掩码
dict(type='Polygon2Mask',
downsample_ratio=downsample_ratio,
mask_overlap=mask_overlap),
]
# 数据集设置
text_transform = [
# 随机加载文本
dict(type='RandomLoadText',
num_neg_samples=(num_classes, num_classes),
max_num_samples=num_training_classes,
padding_to_max=True,
padding_value=''),
# 打包检测输入数据
dict(type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 'flip',
'flip_direction', 'texts'))
]
mosaic_affine_transform = [
# 多模态镶嵌
dict(type='MultiModalMosaic',
img_scale=_base_.img_scale,
pad_val=114.0,
pre_transform=pre_transform),
# YOLOv5CopyPaste 数据增强
dict(type='YOLOv5CopyPaste', prob=_base_.copypaste_prob),
# YOLOv5RandomAffine 数据增强
dict(
type='YOLOv5RandomAffine',
max_rotate_degree=0.0,
max_shear_degree=0.0,
max_aspect_ratio=100.,
scaling_ratio_range=(1 - _base_.affine_scale, 1 _base_.affine_scale),
# 图像尺寸为 (宽度, 高度)
border=(-_base_.img_scale[0] // 2, -_base_.img_scale[1] // 2),
border_val=(114, 114, 114),
min_area_ratio=_base_.min_area_ratio,
use_mask_refine=True)
]
# 训练管道
train_pipeline = [
# 将预处理步骤和镶嵌仿射变换步骤合并
*pre_transform, *mosaic_affine_transform,
# 创建一个字典,指定模型类型为YOLOv5MultiModalMixUp,概率为mixup_prob
dict(type='YOLOv5MultiModalMixUp',
prob=_base_.mixup_prob,
# 将pre_transform和mosaic_affine_transform的元素合并到一个列表中
pre_transform=[*pre_transform, *mosaic_affine_transform]),
# 将last_transform和text_transform的元素合并到一个列表中
*last_transform, *text_transform
# 定义训练管道的第二阶段,包括预处理、YOLOv5KeepRatioResize、LetterResize、YOLOv5RandomAffine等操作
_train_pipeline_stage2 = [
*pre_transform, # 包含预处理操作
dict(type='YOLOv5KeepRatioResize', scale=_base_.img_scale), # YOLOv5KeepRatioResize操作
dict(type='LetterResize', # LetterResize操作
scale=_base_.img_scale,
allow_scale_up=True,
pad_val=dict(img=114.0)),
dict(type='YOLOv5RandomAffine', # YOLOv5RandomAffine操作
max_rotate_degree=0.0,
max_shear_degree=0.0,
scaling_ratio_range=(1 - _base_.affine_scale,
1 _base_.affine_scale),
max_aspect_ratio=_base_.max_aspect_ratio,
border_val=(114, 114, 114),
min_area_ratio=min_area_ratio,
use_mask_refine=use_mask2refine), *last_transform # 包含最后的变换操作
]
# 将_train_pipeline_stage2与text_transform合并为train_pipeline_stage2
train_pipeline_stage2 = [*_train_pipeline_stage2, *text_transform]
# 定义coco_train_dataset,包括数据集类型、数据根目录、注释文件、数据前缀等信息
coco_train_dataset = dict(
_delete_=True,
type='MultiModalDataset',
dataset=dict(type='YOLOv5LVISV1Dataset',
data_root='data/coco',
ann_file='lvis/lvis_v1_train_base.json',
data_prefix=dict(img=''),
filter_cfg=dict(filter_empty_gt=True, min_size=32)),
class_text_path='data/captions/lvis_v1_base_class_captions.json',
pipeline=train_pipeline) # 使用train_pipeline作为管道
# 定义train_dataloader,包括持久化工作进程、每个GPU的批量大小、数据集、数据收集函数等信息
train_dataloader = dict(persistent_workers=persistent_workers,
batch_size=train_batch_size_per_gpu,
collate_fn=dict(type='yolow_collate'),
dataset=coco_train_dataset)
# 定义测试管道,包括加载文本、PackDetInputs等操作
test_pipeline = [
*_base_.test_pipeline[:-1], # 包含基本测试管道的前几个操作
dict(type='LoadText'), # 加载文本操作
dict(type='mmdet.PackDetInputs', # PackDetInputs操作
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape',
'scale_factor', 'pad_param', 'texts'))
]
# 训练设置
# 默认的钩子配置,包括参数调度器和检查点
default_hooks = dict(param_scheduler=dict(scheduler_type='linear',
lr_factor=0.01,
max_epochs=max_epochs),
checkpoint=dict(max_keep_ckpts=-1,
save_best=None,
interval=save_epoch_intervals))
# 自定义的钩子配置列表
custom_hooks = [
dict(type='EMAHook',
ema_type='ExpMomentumEMA',
momentum=0.0001,
update_buffers=True,
strict_load=False,
priority=49),
dict(type='mmdet.PipelineSwitchHook',
switch_epoch=max_epochs - close_mosaic_epochs,
switch_pipeline=train_pipeline_stage2)
]
# 训练配置,包括最大训练轮数、验证间隔、动态间隔等
train_cfg = dict(max_epochs=max_epochs,
val_interval=5,
dynamic_intervals=[((max_epochs - close_mosaic_epochs),
_base_.val_interval_stage2)])
# 优化器包装器配置,包括优化器类型、学习率、权重衰减等
optim_wrapper = dict(optimizer=dict(
_delete_=True,
type='AdamW',
lr=base_lr,
weight_decay=weight_decay,
batch_size_per_gpu=train_batch_size_per_gpu),
paramwise_cfg=dict(bias_decay_mult=0.0,
norm_decay_mult=0.0,
custom_keys={
'backbone.text_model':
dict(lr_mult=0.01),
'logit_scale':
dict(weight_decay=0.0)
}),
constructor='YOLOWv5OptimizerConstructor')
# 评估设置,包括 COCO 验证数据集配置
coco_val_dataset = dict(
_delete_=True,
type='MultiModalDataset',
dataset=dict(type='YOLOv5LVISV1Dataset',
data_root='data/coco/',
test_mode=True,
ann_file='lvis/lvis_v1_val.json',
data_prefix=dict(img=''),
batch_shapes_cfg=None),
# 定义类别文本路径为'data/captions/lvis_v1_class_captions.json',用于存储类别标签的文本信息
class_text_path='data/captions/lvis_v1_class_captions.json',
# 定义数据处理流程为test_pipeline,用于对数据进行预处理和增强操作
pipeline=test_pipeline)
# 创建验证数据加载器,使用 COCO 验证数据集
val_dataloader = dict(dataset=coco_val_dataset)
# 将验证数据加载器赋值给测试数据加载器
test_dataloader = val_dataloader
# 创建验证评估器,类型为 'mmdet.LVISMetric',使用 LVIS 验证数据集的注释文件,评估指标包括边界框和分割
val_evaluator = dict(type='mmdet.LVISMetric',
ann_file='data/coco/lvis/lvis_v1_val.json',
metric=['bbox', 'segm'])
# 将验证评估器赋值给测试评估器
test_evaluator = val_evaluator
# 设置参数为查找未使用的参数
find_unused_parameters = True
.YOLO-Worldconfigssegmentationyolo_world_seg_m_dual_vlpan_2e-4_80e_8gpus_seghead_finetune_lvis.py
代码语言:javascript
复制_base_ = (
'../../third_party/mmyolo/configs/yolov8/yolov8_m_mask-refine_syncbn_fast_8xb16-500e_coco.py'
)
# 定义基础配置文件路径
custom_imports = dict(imports=['yolo_world'], allow_failed_imports=False)
# 自定义导入模块,禁止导入失败
# 超参数设置
num_classes = 1203
num_training_classes = 80
max_epochs = 80 # 最大训练轮数
close_mosaic_epochs = 10
save_epoch_intervals = 5
text_channels = 512
neck_embed_channels = [128, 256, _base_.last_stage_out_channels // 2]
neck_num_heads = [4, 8, _base_.last_stage_out_channels // 2 // 32]
base_lr = 2e-4
weight_decay = 0.05
train_batch_size_per_gpu = 8
load_from = 'pretrained_models/yolo_world_m_clip_base_dual_vlpan_2e-3adamw_32xb16_100e_o365_goldg_train_pretrained-2b7bd1be.pth'
persistent_workers = False
# Polygon2Mask
downsample_ratio = 4
mask_overlap = False
use_mask2refine = True
max_aspect_ratio = 100
min_area_ratio = 0.01
# 模型设置
model = dict(
type='YOLOWorldDetector',
mm_neck=True,
num_train_classes=num_training_classes,
num_test_classes=num_classes,
data_preprocessor=dict(type='YOLOWDetDataPreprocessor'),
backbone=dict(
_delete_=True,
type='MultiModalYOLOBackbone',
image_model={{_base_.model.backbone}},
frozen_stages=4, # 冻结图像骨干网络的阶段
text_model=dict(
type='HuggingCLIPLanguageBackbone',
model_name='openai/clip-vit-base-patch32',
frozen_modules=['all'])),
neck=dict(type='YOLOWorldDualPAFPN',
freeze_all=True,
guide_channels=text_channels,
embed_channels=neck_embed_channels,
num_heads=neck_num_heads,
block_cfg=dict(type='MaxSigmoidCSPLayerWithTwoConv'),
text_enhancder=dict(type='ImagePoolingAttentionModule',
embed_channels=256,
num_heads=8)),
# 定义一个字典,包含YOLOWorldSegHead的相关参数
bbox_head=dict(type='YOLOWorldSegHead',
head_module=dict(type='YOLOWorldSegHeadModule',
embed_dims=text_channels,
num_classes=num_training_classes,
mask_channels=32,
proto_channels=256,
freeze_bbox=True),
mask_overlap=mask_overlap,
loss_mask=dict(type='mmdet.CrossEntropyLoss',
use_sigmoid=True,
reduction='none'),
loss_mask_weight=1.0),
# 定义训练配置,包含分配器的参数
train_cfg=dict(assigner=dict(num_classes=num_training_classes)),
# 定义测试配置,包含mask_thr_binary和fast_test参数
test_cfg=dict(mask_thr_binary=0.5, fast_test=True))
# 定义数据预处理流程的起始部分
pre_transform = [
# 加载图像文件
dict(type='LoadImageFromFile', backend_args=_base_.backend_args),
# 加载标注信息,包括边界框和掩码
dict(type='LoadAnnotations',
with_bbox=True,
with_mask=True,
mask2bbox=True)
]
# 定义数据预处理流程的最后部分
last_transform = [
# 使用 mmdet 库中的 Albu 进行数据增强
dict(type='mmdet.Albu',
transforms=_base_.albu_train_transforms,
bbox_params=dict(type='BboxParams',
format='pascal_voc',
label_fields=['gt_bboxes_labels',
'gt_ignore_flags']),
keymap={
'img': 'image',
'gt_bboxes': 'bboxes'
}),
# 使用 YOLOv5HSVRandomAug 进行数据增强
dict(type='YOLOv5HSVRandomAug'),
# 随机翻转图像
dict(type='mmdet.RandomFlip', prob=0.5),
# 将多边形转换为掩码
dict(type='Polygon2Mask',
downsample_ratio=downsample_ratio,
mask_overlap=mask_overlap),
]
# 数据集设置
text_transform = [
# 随机加载文本信息
dict(type='RandomLoadText',
num_neg_samples=(num_classes, num_classes),
max_num_samples=num_training_classes,
padding_to_max=True,
padding_value=''),
# 打包检测输入信息
dict(type='PackDetInputs',
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', 'flip',
'flip_direction', 'texts'))
]
mosaic_affine_transform = [
# 多模态镶嵌
dict(type='MultiModalMosaic',
img_scale=_base_.img_scale,
pad_val=114.0,
pre_transform=pre_transform),
# YOLOv5CopyPaste 数据增强
dict(type='YOLOv5CopyPaste', prob=_base_.copypaste_prob),
# YOLOv5RandomAffine 数据增强
dict(
type='YOLOv5RandomAffine',
max_rotate_degree=0.0,
max_shear_degree=0.0,
max_aspect_ratio=100.,
scaling_ratio_range=(1 - _base_.affine_scale, 1 _base_.affine_scale),
# 图像缩放比例为 (宽度, 高度)
border=(-_base_.img_scale[0] // 2, -_base_.img_scale[1] // 2),
border_val=(114, 114, 114),
min_area_ratio=_base_.min_area_ratio,
use_mask_refine=True)
]
# 训练流程
train_pipeline = [
# 将数据预处理流程的起始部分和多模态仿射变换部分合并
*pre_transform, *mosaic_affine_transform,
# 创建一个字典,指定模型类型为YOLOv5MultiModalMixUp,概率为mixup_prob
dict(type='YOLOv5MultiModalMixUp',
prob=_base_.mixup_prob,
# 将pre_transform和mosaic_affine_transform的元素合并到一个列表中
pre_transform=[*pre_transform, *mosaic_affine_transform]),
# 将last_transform和text_transform的元素合并到一个列表中
*last_transform, *text_transform
# 定义训练管道的第二阶段,包括预处理、YOLOv5KeepRatioResize、LetterResize、YOLOv5RandomAffine等操作
_train_pipeline_stage2 = [
*pre_transform, # 将pre_transform中的操作展开
dict(type='YOLOv5KeepRatioResize', scale=_base_.img_scale), # 使用YOLOv5KeepRatioResize进行图像缩放
dict(type='LetterResize', # 使用LetterResize进行图像缩放
scale=_base_.img_scale, # 图像缩放比例
allow_scale_up=True, # 允许图像放大
pad_val=dict(img=114.0)), # 图像填充值
dict(type='YOLOv5RandomAffine', # 使用YOLOv5RandomAffine进行随机仿射变换
max_rotate_degree=0.0, # 最大旋转角度
max_shear_degree=0.0, # 最大剪切角度
scaling_ratio_range=(1 - _base_.affine_scale, 1 _base_.affine_scale), # 缩放比例范围
max_aspect_ratio=_base_.max_aspect_ratio, # 最大长宽比
border_val=(114, 114, 114), # 边界填充值
min_area_ratio=min_area_ratio, # 最小区域比例
use_mask_refine=use_mask2refine), # 是否使用mask进行细化
*last_transform # 将last_transform中的操作展开
]
# 将_train_pipeline_stage2和text_transform合并为train_pipeline_stage2
train_pipeline_stage2 = [*_train_pipeline_stage2, *text_transform]
# 定义coco_train_dataset,包括数据集类型、数据根目录、注释文件、数据前缀等信息
coco_train_dataset = dict(
_delete_=True, # 删除标记
type='MultiModalDataset', # 数据集类型
dataset=dict(type='YOLOv5LVISV1Dataset', # 数据集类型为YOLOv5LVISV1Dataset
data_root='data/coco', # 数据根目录
ann_file='lvis/lvis_v1_train_base.json', # 注释文件
data_prefix=dict(img=''), # 数据前缀
filter_cfg=dict(filter_empty_gt=True, min_size=32)), # 过滤配置
class_text_path='data/captions/lvis_v1_base_class_captions.json', # 类别文本路径
pipeline=train_pipeline) # 数据处理管道
# 定义train_dataloader,包括持久化工作进程、每个GPU的训练批量大小、数据集、数据集合并函数等信息
train_dataloader = dict(persistent_workers=persistent_workers, # 持久化工作进程
batch_size=train_batch_size_per_gpu, # 每个GPU的训练批量大小
collate_fn=dict(type='yolow_collate'), # 数据集合并函数
dataset=coco_train_dataset) # 数据集
# 定义测试管道,包括加载文本、PackDetInputs等操作
test_pipeline = [
*_base_.test_pipeline[:-1], # 将_base_.test_pipeline中的操作展开,去掉最后一个操作
dict(type='LoadText'), # 加载文本
dict(type='mmdet.PackDetInputs', # 使用mmdet.PackDetInputs打包检测输入
meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', # 元数据键
'scale_factor', 'pad_param', 'texts')) # 元数据键
]
# 默认的钩子配置,包括参数调度器和检查点
default_hooks = dict(param_scheduler=dict(scheduler_type='linear',
lr_factor=0.01,
max_epochs=max_epochs),
checkpoint=dict(max_keep_ckpts=-1,
save_best=None,
interval=save_epoch_intervals))
# 自定义的钩子配置
custom_hooks = [
dict(type='EMAHook',
ema_type='ExpMomentumEMA',
momentum=0.0001,
update_buffers=True,
strict_load=False,
priority=49),
dict(type='mmdet.PipelineSwitchHook',
switch_epoch=max_epochs - close_mosaic_epochs,
switch_pipeline=train_pipeline_stage2)
]
# 训练配置,包括最大训练周期、验证间隔、动态间隔
train_cfg = dict(max_epochs=max_epochs,
val_interval=5,
dynamic_intervals=[((max_epochs - close_mosaic_epochs),
_base_.val_interval_stage2)])
# 优化器包装器配置,包括优化器类型、学习率、权重衰减
optim_wrapper = dict(optimizer=dict(
_delete_=True,
type='AdamW',
lr=base_lr,
weight_decay=weight_decay,
# 设置每个 GPU 的训练批量大小
batch_size_per_gpu=train_batch_size_per_gpu),
# 针对参数进行配置,设置偏置和归一化的衰减倍数为0
paramwise_cfg=dict(bias_decay_mult=0.0,
norm_decay_mult=0.0,
custom_keys={
# 针对文本模型的学习率倍数设置为0.01
'backbone.text_model':
dict(lr_mult=0.01),
# 针对logit_scale的权重衰减设置为0.0
'logit_scale':
dict(weight_decay=0.0),
# 针对neck的学习率倍数设置为0.0
'neck':
dict(lr_mult=0.0),
# 针对head_module.reg_preds的学习率倍数设置为0.0
'head.head_module.reg_preds':
dict(lr_mult=0.0),
# 针对head_module.cls_preds的学习率倍数设置为0.0
'head.head_module.cls_preds':
dict(lr_mult=0.0),
# 针对head_module.cls_contrasts的学习率倍数设置为0.0
'head.head_module.cls_contrasts':
dict(lr_mult=0.0)
}),
# 设置构造函数为'YOLOWv5OptimizerConstructor'
constructor='YOLOWv5OptimizerConstructor')
# 设置评估参数
coco_val_dataset = dict(
_delete_=True, # 删除该参数
type='MultiModalDataset', # 数据集类型为多模态数据集
dataset=dict(type='YOLOv5LVISV1Dataset', # 数据集类型为YOLOv5LVISV1Dataset
data_root='data/coco/', # 数据根目录
test_mode=True, # 测试模式为True
ann_file='lvis/lvis_v1_val.json', # 标注文件路径
data_prefix=dict(img=''), # 数据前缀
batch_shapes_cfg=None), # 批量形状配置为空
class_text_path='data/captions/lvis_v1_class_captions.json', # 类别文本路径
pipeline=test_pipeline) # 测试管道
val_dataloader = dict(dataset=coco_val_dataset) # 验证数据加载器设置为coco_val_dataset
test_dataloader = val_dataloader # 测试数据加载器设置为验证数据加载器
val_evaluator = dict(type='mmdet.LVISMetric', # 评估器类型为mmdet.LVISMetric
ann_file='data/coco/lvis/lvis_v1_val.json', # 标注文件路径
metric=['bbox', 'segm']) # 评估指标为bbox和segm
test_evaluator = val_evaluator # 测试评估器设置为验证评估器
find_unused_parameters = True # 查找未使用的参数为True
.YOLO-Worlddemo.py
代码语言:javascript
复制# 导入必要的库
import argparse
import os.path as osp
from functools import partial
import cv2
import torch
import gradio as gr
import numpy as np
import supervision as sv
from PIL import Image
from torchvision.ops import nms
from mmengine.config import Config, DictAction
from mmengine.runner import Runner
from mmengine.runner.amp import autocast
from mmengine.dataset import Compose
from mmdet.datasets import CocoDataset
from mmyolo.registry import RUNNERS
# 创建边界框标注器和标签标注器对象
BOUNDING_BOX_ANNOTATOR = sv.BoundingBoxAnnotator()
LABEL_ANNOTATOR = sv.LabelAnnotator()
# 解析命令行参数
def parse_args():
parser = argparse.ArgumentParser(description='YOLO-World Demo')
parser.add_argument('config', help='test config file path')
parser.add_argument('checkpoint', help='checkpoint file')
parser.add_argument(
'--work-dir',
help='the directory to save the file containing evaluation metrics')
parser.add_argument(
'--cfg-options',
nargs=' ',
action=DictAction,
help='override some settings in the used config, the key-value pair '
'in xxx=yyy format will be merged into config file. If the value to '
'be overwritten is a list, it should be like key="[a,b]" or key=a,b '
'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" '
'Note that the quotation marks are necessary and that no white space '
'is allowed.')
args = parser.parse_args()
return args
# 运行图像处理
def run_image(runner,
image,
text,
max_num_boxes,
score_thr,
nms_thr,
image_path='./work_dirs/demo.png'):
# 保存图像到指定路径
image.save(image_path)
# 将文本分割成列表
texts = [[t.strip()] for t in text.split(',')] [[' ']]
# 构建数据信息字典
data_info = dict(img_id=0, img_path=image_path, texts=texts)
# 运行处理管道
data_info = runner.pipeline(data_info)
# 构建数据批次
data_batch = dict(inputs=data_info['inputs'].unsqueeze(0),
data_samples=[data_info['data_samples']])
# 关闭自动混合精度和禁用梯度计算
with autocast(enabled=False), torch.no_grad():
# 运行模型的测试步骤,获取输出
output = runner.model.test_step(data_batch)[0]
# 获取预测实例
pred_instances = output.pred_instances
# 使用非极大值抑制(NMS)筛选预测实例
keep = nms(pred_instances.bboxes, pred_instances.scores, iou_threshold=nms_thr)
pred_instances = pred_instances[keep]
# 根据置信度阈值筛选预测实例
pred_instances = pred_instances[pred_instances.scores.float() > score_thr]
# 如果预测实例数量超过最大边界框数目限制
if len(pred_instances.scores) > max_num_boxes:
# 保留置信度最高的边界框
indices = pred_instances.scores.float().topk(max_num_boxes)[1]
pred_instances = pred_instances[indices]
# 将预测实例转换为 NumPy 数组
pred_instances = pred_instances.cpu().numpy()
# 创建检测结果对象
detections = sv.Detections(
xyxy=pred_instances['bboxes'],
class_id=pred_instances['labels'],
confidence=pred_instances['scores']
)
# 生成标签列表
labels = [
f"{texts[class_id][0]} {confidence:0.2f}"
for class_id, confidence
in zip(detections.class_id, detections.confidence)
]
# 将图像转换为 NumPy 数组
image = np.array(image)
# 将图像从 RGB 转换为 BGR 格式
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
# 在图像上绘制边界框
image = BOUNDING_BOX_ANNOTATOR.annotate(image, detections)
# 在图像上添加标签
image = LABEL_ANNOTATOR.annotate(image, detections, labels=labels)
# 将图像从 BGR 转换为 RGB 格式
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 创建图像对象
image = Image.fromarray(image)
# 返回处理后的图像
return image
def demo(runner, args):
# 如果当前脚本作为主程序运行
if __name__ == '__main__':
# 解析命令行参数
args = parse_args()
# 从配置文件加载配置信息
cfg = Config.fromfile(args.config)
# 如果有额外的配置选项,则合并到配置中
if args.cfg_options is not None:
cfg.merge_from_dict(args.cfg_options)
# 如果命令行参数中指定了工作目录,则使用该目录,否则使用配置中的工作目录,如果配置中也没有,则使用默认目录
if args.work_dir is not None:
cfg.work_dir = args.work_dir
elif cfg.get('work_dir', None) is None:
cfg.work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0])
# 加载模型参数
cfg.load_from = args.checkpoint
# 如果配置中没有指定运行器类型,则根据配置创建运行器对象
if 'runner_type' not in cfg:
runner = Runner.from_cfg(cfg)
else:
# 否则根据配置中的运行器类型创建运行器对象
runner = RUNNERS.build(cfg)
# 运行前的钩子函数
runner.call_hook('before_run')
# 加载或恢复模型参数
runner.load_or_resume()
# 获取测试数据集的数据处理流程
pipeline = cfg.test_dataloader.dataset.pipeline
# 创建数据处理流程对象
runner.pipeline = Compose(pipeline)
# 设置模型为评估模式
runner.model.eval()
# 运行演示
demo(runner, args)
.YOLO-Worlddeploydeploy.py
代码语言:javascript
复制# 导入必要的库
import argparse # 用于解析命令行参数
import logging # 用于记录日志
import os # 用于操作系统相关功能
import os.path as osp # 用于操作文件路径
from functools import partial # 用于创建偏函数
import mmengine # 导入 mmengine 库
import torch.multiprocessing as mp # 导入多进程库
from torch.multiprocessing import Process, set_start_method # 导入多进程相关函数
from mmdeploy.apis import (create_calib_input_data, extract_model, # 导入一些部署相关的函数
get_predefined_partition_cfg, torch2onnx,
torch2torchscript, visualize_model)
from mmdeploy.apis.core import PIPELINE_MANAGER # 导入核心部署管理器
from mmdeploy.apis.utils import to_backend # 导入转换到后端的函数
from mmdeploy.backend.sdk.export_info import export2SDK # 导入导出到 SDK 的函数
from mmdeploy.utils import (IR, Backend, get_backend, get_calib_filename, # 导入一些工具函数
get_ir_config, get_partition_config,
get_root_logger, load_config, target_wrapper)
def parse_args():
# 创建命令行参数解析器
parser = argparse.ArgumentParser(description='Export model to backends.')
# 添加命令行参数
parser.add_argument('deploy_cfg', help='deploy config path') # 部署配置文件路径
parser.add_argument('model_cfg', help='model config path') # 模型配置文件路径
parser.add_argument('checkpoint', help='model checkpoint path') # 模型检查点路径
parser.add_argument('img', help='image used to convert model model') # 用于转换模型的图像
parser.add_argument(
'--test-img',
default=None,
type=str,
nargs=' ',
help='image used to test model') # 用于测试模型的图像
parser.add_argument(
'--work-dir',
default=os.getcwd(),
help='the dir to save logs and models') # 保存日志和模型的目录
parser.add_argument(
'--calib-dataset-cfg',
help='dataset config path used to calibrate in int8 mode. If not
specified, it will use "val" dataset in model config instead.',
default=None) # 用于在 int8 模式下校准的数据集配置文件路径
parser.add_argument(
'--device', help='device used for conversion', default='cpu') # 用于转换的设备
parser.add_argument(
'--log-level',
help='set log level',
default='INFO',
choices=list(logging._nameToLevel.keys())) # 设置日志级别
# 添加命令行参数,用于显示检测输出
parser.add_argument(
'--show', action='store_true', help='Show detection outputs')
# 添加命令行参数,用于输出 SDK 的信息
parser.add_argument(
'--dump-info', action='store_true', help='Output information for SDK')
# 添加命令行参数,指定用于量化模型的图像目录
parser.add_argument(
'--quant-image-dir',
default=None,
help='Image directory for quantize model.')
# 添加命令行参数,用于将模型量化为低位
parser.add_argument(
'--quant', action='store_true', help='Quantize model to low bit.')
# 添加命令行参数,指定远程设备上进行推理的 IP 地址和端口
parser.add_argument(
'--uri',
default='192.168.1.1:60000',
help='Remote ipv4:port or ipv6:port for inference on edge device.')
# 解析命令行参数
args = parser.parse_args()
# 返回解析后的参数
return args
# 创建一个进程,执行指定的目标函数,并传入参数和关键字参数,可选地返回一个值
def create_process(name, target, args, kwargs, ret_value=None):
# 获取根日志记录器
logger = get_root_logger()
# 记录进程开始信息
logger.info(f'{name} start.')
# 获取日志级别
log_level = logger.level
# 创建一个包装函数,用于处理目标函数的执行结果和日志记录
wrap_func = partial(target_wrapper, target, log_level, ret_value)
# 创建一个进程对象,指定目标函数、参数和关键字参数
process = Process(target=wrap_func, args=args, kwargs=kwargs)
# 启动进程
process.start()
# 等待进程结束
process.join()
# 如果有返回值,检查返回值是否为0,记录日志并退出程序
if ret_value is not None:
if ret_value.value != 0:
logger.error(f'{name} failed.')
exit(1)
else:
logger.info(f'{name} success.')
# 根据中间表示类型返回对应的转换函数
def torch2ir(ir_type: IR):
"""Return the conversion function from torch to the intermediate
representation.
Args:
ir_type (IR): The type of the intermediate representation.
"""
if ir_type == IR.ONNX:
return torch2onnx
elif ir_type == IR.TORCHSCRIPT:
return torch2torchscript
else:
raise KeyError(f'Unexpected IR type {ir_type}')
# 主函数
def main():
# 解析命令行参数
args = parse_args()
# 设置进程启动方法为'spawn'
set_start_method('spawn', force=True)
# 获取根日志记录器
logger = get_root_logger()
# 获取日志级别
log_level = logging.getLevelName(args.log_level)
# 设置日志级别
logger.setLevel(log_level)
# 定义一系列处理函数
pipeline_funcs = [
torch2onnx, torch2torchscript, extract_model, create_calib_input_data
]
# 启用多进程模式,并指定处理函数
PIPELINE_MANAGER.enable_multiprocess(True, pipeline_funcs)
# 设置处理函数的日志级别
PIPELINE_MANAGER.set_log_level(log_level, pipeline_funcs)
# 获取部署配置路径、模型配置路径、检查点路径、量化标志和量化图片目录
deploy_cfg_path = args.deploy_cfg
model_cfg_path = args.model_cfg
checkpoint_path = args.checkpoint
quant = args.quant
quant_image_dir = args.quant_image_dir
# 加载部署配置和模型配置
deploy_cfg, model_cfg = load_config(deploy_cfg_path, model_cfg_path)
# 如果需要,创建工作目录
mmengine.mkdir_or_exist(osp.abspath(args.work_dir))
# 如果需要,导出到SDK
if args.dump_info:
export2SDK(
deploy_cfg,
model_cfg,
args.work_dir,
pth=checkpoint_path,
device=args.device)
# 创建一个共享变量,用于存储返回值
ret_value = mp.Value('d', 0, lock=False)
# 转换为中间表示
ir_config = get_ir_config(deploy_cfg)
# 获取保存 IR 结果的文件名
ir_save_file = ir_config['save_file']
# 获取 IR 类型
ir_type = IR.get(ir_config['type'])
# 调用 torch2ir 函数将模型转换为 IR
torch2ir(ir_type)(
args.img,
args.work_dir,
ir_save_file,
deploy_cfg_path,
model_cfg_path,
checkpoint_path,
device=args.device)
# 转换后的 IR 文件列表
ir_files = [osp.join(args.work_dir, ir_save_file)]
# 获取模型分区配置
partition_cfgs = get_partition_config(deploy_cfg)
if partition_cfgs is not None:
if 'partition_cfg' in partition_cfgs:
partition_cfgs = partition_cfgs.get('partition_cfg', None)
else:
assert 'type' in partition_cfgs
partition_cfgs = get_predefined_partition_cfg(
deploy_cfg, partition_cfgs['type'])
# 原始 IR 文件
origin_ir_file = ir_files[0]
ir_files = []
# 遍历分区配置,对模型进行分区
for partition_cfg in partition_cfgs:
save_file = partition_cfg['save_file']
save_path = osp.join(args.work_dir, save_file)
start = partition_cfg['start']
end = partition_cfg['end']
dynamic_axes = partition_cfg.get('dynamic_axes', None)
# 提取模型的部分并保存
extract_model(
origin_ir_file,
start,
end,
dynamic_axes=dynamic_axes,
save_file=save_path)
ir_files.append(save_path)
# 获取校准数据文件名
calib_filename = get_calib_filename(deploy_cfg)
if calib_filename is not None:
calib_path = osp.join(args.work_dir, calib_filename)
# 创建校准输入数据
create_calib_input_data(
calib_path,
deploy_cfg_path,
model_cfg_path,
checkpoint_path,
dataset_cfg=args.calib_dataset_cfg,
dataset_type='val',
device=args.device)
# 后端文件列表
backend_files = ir_files
# 获取后端类型
backend = get_backend(deploy_cfg)
# 预处理部署配置
# 如果选择的后端是RKNN
if backend == Backend.RKNN:
# TODO: 在将来将此功能添加到任务处理器中
# 导入临时文件模块
import tempfile
# 从mmdeploy.utils中导入必要的函数
from mmdeploy.utils import (get_common_config, get_normalization,
get_quantization_config,
get_rknn_quantization)
# 获取量化配置
quantization_cfg = get_quantization_config(deploy_cfg)
# 获取通用配置
common_params = get_common_config(deploy_cfg)
# 如果需要RKNN量化
if get_rknn_quantization(deploy_cfg) is True:
# 获取归一化转换参数
transform = get_normalization(model_cfg)
# 更新通用参数,包括均值和标准差
common_params.update(
dict(
mean_values=[transform['mean']],
std_values=[transform['std']]))
# 创建临时文件用于存储数据集文件路径
dataset_file = tempfile.NamedTemporaryFile(suffix='.txt').name
# 将图像文件的绝对路径写入数据集文件
with open(dataset_file, 'w') as f:
f.writelines([osp.abspath(args.img)])
# 如果量化配置中未指定数据集,则将数据集文件路径添加到量化配置中
if quantization_cfg.get('dataset', None) is None:
quantization_cfg['dataset'] = dataset_file
# 如果选择的后端是ASCEND
if backend == Backend.ASCEND:
# TODO: 在将来将此功能添加到后端管理器中
# 如果需要输出信息
if args.dump_info:
# 从mmdeploy.backend.ascend中导入更新SDK管道的函数
from mmdeploy.backend.ascend import update_sdk_pipeline
# 更新SDK管道
update_sdk_pipeline(args.work_dir)
# 如果后端是VACC
if backend == Backend.VACC:
# TODO: 将此部分在未来添加到任务处理器中
# 导入获取量化数据的模块
from onnx2vacc_quant_dataset import get_quant
# 导入获取模型输入的工具函数
from mmdeploy.utils import get_model_inputs
# 加载部署配置和模型配置
deploy_cfg, model_cfg = load_config(deploy_cfg_path, model_cfg_path)
# 获取模型输入
model_inputs = get_model_inputs(deploy_cfg)
# 遍历ONNX文件路径和模型输入
for onnx_path, model_input in zip(ir_files, model_inputs):
# 获取量化模式
quant_mode = model_input.get('qconfig', {}).get('dtype', 'fp16')
# 确保量化模式为'int8'或'fp16'
assert quant_mode in ['int8', 'fp16'], quant_mode ' not support now'
shape_dict = model_input.get('shape', {})
# 如果量化模式为'int8'
if quant_mode == 'int8':
# 创建处理过程
create_process(
'vacc quant dataset',
target=get_quant,
args=(deploy_cfg, model_cfg, shape_dict, checkpoint_path,
args.work_dir, args.device),
kwargs=dict(),
ret_value=ret_value)
# 设置日志级别
PIPELINE_MANAGER.set_log_level(log_level, [to_backend])
# 如果后端是TensorRT,启用多进程
if backend == Backend.TENSORRT:
PIPELINE_MANAGER.enable_multiprocess(True, [to_backend])
# 将转换后的文件传递给后端处理
backend_files = to_backend(
backend,
ir_files,
work_dir=args.work_dir,
deploy_cfg=deploy_cfg,
log_level=log_level,
device=args.device,
uri=args.uri)
# 进行ncnn量化
# 如果后端为NCNN且需要量化
if backend == Backend.NCNN and quant:
# 导入获取量化表的函数
from onnx2ncnn_quant_table import get_table
# 导入NCNN相关函数
from mmdeploy.apis.ncnn import get_quant_model_file, ncnn2int8
# 获取模型参数路径列表
model_param_paths = backend_files[::2]
# 获取模型二进制文件路径列表
model_bin_paths = backend_files[1::2]
# 清空后端文件列表
backend_files = []
# 遍历ONNX文件路径、模型参数路径、模型二进制文件路径
for onnx_path, model_param_path, model_bin_path in zip(
ir_files, model_param_paths, model_bin_paths):
# 加载部署配置和模型配置
deploy_cfg, model_cfg = load_config(deploy_cfg_path,
model_cfg_path)
# 获取量化后的ONNX文件、量化表、量化参数、量化二进制文件
quant_onnx, quant_table, quant_param, quant_bin = get_quant_model_file(
onnx_path, args.work_dir)
# 创建进程,获取量化表
create_process(
'ncnn quant table',
target=get_table,
args=(onnx_path, deploy_cfg, model_cfg, quant_onnx,
quant_table, quant_image_dir, args.device),
kwargs=dict(),
ret_value=ret_value)
# 创建进程,进行NCNN量化
create_process(
'ncnn_int8',
target=ncnn2int8,
args=(model_param_path, model_bin_path, quant_table,
quant_param, quant_bin),
kwargs=dict(),
ret_value=ret_value)
# 将量化参数和量化二进制文件添加到后端文件列表中
backend_files = [quant_param, quant_bin]
# 如果未指定测试图片,则使用默认图片
if args.test_img is None:
args.test_img = args.img
# 额外参数,包括后端类型、输出文件路径、是否显示结果
extra = dict(
backend=backend,
output_file=osp.join(args.work_dir, f'output_{backend.value}.jpg'),
show_result=args.show)
# 如果后端为SNPE,则添加URI参数
if backend == Backend.SNPE:
extra['uri'] = args.uri
# 获取后端推理结果,并尝试渲染
create_process(
f'visualize {backend.value} model',
target=visualize_model,
args=(model_cfg_path, deploy_cfg_path, backend_files, args.test_img,
args.device),
kwargs=extra,
ret_value=ret_value)
# 获取PyTorch模型推理结果,尝试可视化(如果可能)
# 创建一个进程,用于可视化 PyTorch 模型
create_process(
'visualize pytorch model', # 进程名称
target=visualize_model, # 目标函数为 visualize_model
args=(model_cfg_path, deploy_cfg_path, [checkpoint_path], args.test_img, args.device), # 参数列表
kwargs=dict(
backend=Backend.PYTORCH, # 使用 PyTorch 后端
output_file=osp.join(args.work_dir, 'output_pytorch.jpg'), # 输出文件路径
show_result=args.show), # 是否显示结果
ret_value=ret_value) # 返回值为 ret_value
# 记录信息到日志
logger.info('All process success.')
# 如果当前脚本被直接执行,则调用主函数
if __name__ == '__main__':
main()
.YOLO-Worlddeploydeploy_test.py
代码语言:javascript
复制# 导入必要的库
import argparse
import os.path as osp
from copy import deepcopy
# 导入自定义模块
from mmengine import DictAction
from mmdeploy.apis import build_task_processor
from mmdeploy.utils.config_utils import load_config
from mmdeploy.utils.timer import TimeCounter
# 解析命令行参数
def parse_args():
# 创建参数解析器
parser = argparse.ArgumentParser(description='MMDeploy test (and eval) a backend.')
# 添加命令行参数
parser.add_argument('deploy_cfg', help='Deploy config path')
parser.add_argument('model_cfg', help='Model config path')
parser.add_argument('--model', type=str, nargs=' ', help='Input model files.')
parser.add_argument('--device', help='device used for conversion', default='cpu')
parser.add_argument('--work-dir', default='./work_dir', help='the directory to save the file containing evaluation metrics')
parser.add_argument('--cfg-options', nargs=' ', action=DictAction, help='override some settings in the used config, the key-value pair in xxx=yyy format will be merged into config file. If the value to be overwritten is a list, it should be like key="[a,b]" or key=a,b It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" Note that the quotation marks are necessary and that no white space is allowed.')
parser.add_argument('--show', action='store_true', help='show results')
parser.add_argument('--show-dir', help='directory where painted images will be saved')
parser.add_argument('--interval', type=int, default=1, help='visualize per interval samples.')
parser.add_argument('--wait-time', type=float, default=2, help='display time of every window. (second)')
parser.add_argument('--log2file', type=str, help='log evaluation results and speed to file', default=None)
# 添加命令行参数,用于激活速度测试
parser.add_argument(
'--speed-test', action='store_true', help='activate speed test')
# 添加命令行参数,用于设置预热次数,在计算推理时间之前需要设置速度测试
parser.add_argument(
'--warmup',
type=int,
help='warmup before counting inference elapse, require setting '
'speed-test first',
default=10)
# 添加命令行参数,用于设置日志输出间隔,在设置速度测试之前需要设置
parser.add_argument(
'--log-interval',
type=int,
help='the interval between each log, require setting '
'speed-test first',
default=100)
# 添加命令行参数,用于设置测试的批次大小,会覆盖数据配置中的 `samples_per_gpu`
parser.add_argument(
'--batch-size',
type=int,
default=1,
help='the batch size for test, would override `samples_per_gpu`'
'in data config.')
# 添加命令行参数,用于设置远程推理设备的 IP 地址和端口
parser.add_argument(
'--uri',
action='store_true',
default='192.168.1.1:60000',
help='Remote ipv4:port or ipv6:port for inference on edge device.')
# 解析命令行参数
args = parser.parse_args()
# 返回解析后的参数
return args
def main():
# 解析命令行参数
args = parse_args()
# 获取部署配置文件路径和模型配置文件路径
deploy_cfg_path = args.deploy_cfg
model_cfg_path = args.model_cfg
# 加载部署配置和模型配置
deploy_cfg, model_cfg = load_config(deploy_cfg_path, model_cfg_path)
# 确定工作目录的优先级:命令行参数 > 文件中的段落 > 文件名
if args.work_dir is not None:
# 如果命令行参数中指定了工作目录,则更新配置
work_dir = args.work_dir
elif model_cfg.get('work_dir', None) is None:
# 如果配置文件中未指定工作目录,则使用配置文件名作为默认工作目录
work_dir = osp.join('./work_dirs', osp.splitext(osp.basename(args.config))[0])
# 合并模型配置的选项
if args.cfg_options is not None:
model_cfg.merge_from_dict(args.cfg_options)
# 构建任务处理器
task_processor = build_task_processor(model_cfg, deploy_cfg, args.device)
# 准备数据集加载器
test_dataloader = deepcopy(model_cfg['test_dataloader'])
if isinstance(test_dataloader, list):
dataset = []
for loader in test_dataloader:
# 构建数据集
ds = task_processor.build_dataset(loader['dataset'])
dataset.append(ds)
loader['dataset'] = ds
loader['batch_size'] = args.batch_size
loader = task_processor.build_dataloader(loader)
dataloader = test_dataloader
else:
test_dataloader['batch_size'] = args.batch_size
dataset = task_processor.build_dataset(test_dataloader['dataset'])
test_dataloader['dataset'] = dataset
dataloader = task_processor.build_dataloader(test_dataloader)
# 加载后端模型
model = task_processor.build_backend_model(
args.model,
data_preprocessor_updater=task_processor.update_data_preprocessor)
destroy_model = model.destroy
is_device_cpu = (args.device == 'cpu')
# 使用任务处理器构建测试运行器,传入模型、工作目录、是否记录日志到文件、是否展示测试结果、展示目录、等待时间、间隔时间、数据加载器等参数
runner = task_processor.build_test_runner(
model,
work_dir,
log_file=args.log2file,
show=args.show,
show_dir=args.show_dir,
wait_time=args.wait_time,
interval=args.interval,
dataloader=dataloader)
# 如果需要进行速度测试
if args.speed_test:
# 根据设备是否为 CPU 决定是否需要同步
with_sync = not is_device_cpu
# 激活时间计数器,设置预热次数、日志间隔、是否同步、记录日志到文件、批处理大小等参数
with TimeCounter.activate(
warmup=args.warmup,
log_interval=args.log_interval,
with_sync=with_sync,
file=args.log2file,
batch_size=args.batch_size):
# 运行测试
runner.test()
else:
# 运行测试
runner.test()
# 仅在后端需要显式清理时生效(例如 Ascend)
destroy_model()
# 如果当前脚本被直接执行,则调用主函数
if __name__ == '__main__':
main()