系统环境:
ubuntu16.04
cuda:10.0(此处一定注意检查自己的环境,关乎到后面cudatoolkit版本的安装问题)
默认大家都已经安装好 anaconda3 了,如果没有安装的,可以去官网下载一个,直接安装即可。
conda create -n mmdetection python=3.7 (mmdetection虚拟环境的名字,可以自己设定)
conda activate mmdetection (激活虚拟环境)
conda install pytorch torchvision cudatoolkit=10.0 -c pytorch
注意:此处的cudatoolkit=10.0是对应你的cuda版本的,如果你的cuda版本是 9.0/ 9.2/ 10.1,那么相应改为cudatoolkit=9.0/ 9.2/ 10.1,不知道自己的 cuda 版本?去 /usr/local/ 下去看。
conda install cython
git clone https://github.com/open-mmlab/mmdetection.git (下载)
cd mmdetection
pip install -r requirements/build.txt (安装需要的组件)
pip install “git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI” (安装pycocotools)
pip install -v -e . # or “python setup.py develop”
安装过程如下:
(mmdetection) bubble@XPS-8930:~/mmdetection/0827/mmdetection$ python setup.py develop
Compiling mmdet/ops/nms/src/soft_nms_cpu.pyx because it changed.
[1/1] Cythonizing mmdet/ops/nms/src/soft_nms_cpu.pyx
/home/bubble/anaconda3/envs/mmdetection/lib/python3.7/site-packages/setuptools/dist.py:474: UserWarning: Normalizing '1.0.rc0+bfce31c' to '1.0rc0+bfce31c'
normalized_version,
running develop
running egg_info
...
...
Using /home/bubble/anaconda3/envs/mmdetection/lib/python3.7/site-packages
Searching for setuptools==41.2.0
Best match: setuptools 41.2.0
Adding setuptools 41.2.0 to easy-install.pth file
Installing easy_install script to /home/bubble/anaconda3/envs/mmdetection/bin
Using /home/bubble/anaconda3/envs/mmdetection/lib/python3.7/site-packages
Searching for decorator==4.4.0
Best match: decorator 4.4.0
Adding decorator 4.4.0 to easy-install.pth file
Using /home/bubble/anaconda3/envs/mmdetection/lib/python3.7/site-packages
Finished processing dependencies for mmdet==1.0rc0+bfce31c
1)下载cocoapi:git clone https://github.com/cocodataset/cocoapi.git
2)进入cocoAPI/PythonAPI目录,执行
python setup.py build_ext --inplace
python setup.py build_ext install
命令行进入 python 环境之后测试
Python 3.7.8 | packaged by conda-forge | (default, Jul 23 2020, 03:54:19)
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch
>>> torch.__version__
'1.4.0'
>>> torch.cuda.is_available()
True
>>>
至此,mmdetection环境配置成功。
(可参照我博客另一篇文章https://blog.csdn.net/qq_36756866/article/details/105269137)
制作voc数据集的第一步就是按voc数据集的格式创建好文件夹,下面是文件夹的组织方式,Annotations中存放图片的labelImg标注文件,JPEGImages存放图片数据。
可以看到Main文件夹下存放了四个txt文件,这些文件里面的内容其实就是将数据集打乱并划分为测试集,训练集,训练验证集,验证集之后的文件名。在网络训练过程中,可以通过文件名来索引训练样本。这四个文件可由 gen_txt.py 来生成。
import os
import random
trainval_percent = 0.8 # trainval数据集占所有数据的比例
train_percent = 0.8 # train数据集占trainval数据的比例
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)
ftrainval = open('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
上述代码分割数据集,训练集占80%,测试集占20%,注意自己的文件路径,可能需要根据自己的存放位置进行修改。
cd /mmdetection/configs/base/datasets 进入目录后打开voc0712.py
# dataset settings
dataset_type = 'VOCDataset' # 数据集类型
# data_root = 'data/VOCdevkit/'
data_root = '/home/trainingai/zyang/darknet_MSW/darknet/' # VOC数据集根目录
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations', with_bbox=True),
dict(type='Resize', img_scale=(1000, 600), keep_ratio=True), # train data size
dict(type='RandomFlip', flip_ratio=0.5),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='DefaultFormatBundle'),
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
]
test_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='MultiScaleFlipAug',
img_scale=(1000, 600), # test data size
flip=False,
transforms=[
dict(type='Resize', keep_ratio=True),
dict(type='RandomFlip'),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(type='ImageToTensor', keys=['img']),
dict(type='Collect', keys=['img']),
])
]
data = dict(
samples_per_gpu=8, # 每个gpu计算的图像数量 batchsize
workers_per_gpu=2, # 每个gpu分配的线程数
train=dict(
type='RepeatDataset',
times=3,
dataset=dict(
type=dataset_type, # 数据集类型
ann_file=[
data_root + 'VOC2007/ImageSets/Main/train.txt',
# data_root + 'VOC2012/ImageSets/Main/trainval.txt'
],
img_prefix=[data_root + 'VOC2007/'],
# img_prefix=[data_root + 'VOC2007/', data_root + 'VOC2012/'],
pipeline=train_pipeline)),
val=dict(
type=dataset_type,
ann_file=data_root + 'VOC2007/ImageSets/Main/test.txt',
img_prefix=data_root + 'VOC2007/', # 数据集的图片路径
pipeline=test_pipeline),
test=dict(
type=dataset_type,
ann_file=data_root + 'VOC2007/ImageSets/Main/test.txt',
img_prefix=data_root + 'VOC2007/',
pipeline=test_pipeline))
evaluation = dict(interval=1, metric='mAP')
在data的配置 要删除屏蔽VOC2012的路径,和VOC2012变量 保存文件。
cd /mmdetection/mmdet/datasets 进入目录后打开voc.py文件
这个CLASSE 是VOC标签的类别 我们要换成自己数据集的类别标签
cd /mmdetection/mmdet/core/evaluation 进入目录后打开class_names.py 文件
修改 voc_classes() 函数返回的标签,换成自己数据集的标签 保存退出
cd mmdetection/configs/faster_rcnn 我们这次选用faster_rcnn 模型训练,进入目录后打开faster_rcnn_r50_fpn_1x_coco.py文件
faster_rcnn_r50_fpn_1xcoco.py文件里面调用了三个文件,第一个是模型配置文件,第二个是数据集配置文件,后来两个是配置学习率,迭代次数,模型加载路径等等,我们把原来COCO_detection.py 修改成VOC0712.py 文件
cd /mmdetection/configs/base/models 进入目录后打开 faster_rcnn_r50fpn.py 文件 ,修改num_classes 数量,num_classes 的值等于类别数量,注意不需要加背景了
以上就是需要修改的内容,修改完成后开始训练模型
指定GPU训练
CUDA_VISIBLE_DEVICES=0 python3 ./tools/train.py ./configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py
附上一张正在训练的日志截图
训练完成后可以参考/mmdetection/demo/image_demo.py文件进行测试
测试代码命令如下:
CUDA_VISIBLE_DEVICES=0 python ./tools/test.py ./configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py work_dirs/faster_rcnn_r50_fpn_1x_coco/latest.pth --out model/result.pkl --eval mAP
------./tools/test.py 测试代码
------./configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py 配置文件(同训练过程)
------work_dirs/faster_rcnn_r50_fpn_1x_coco/latest.pth 训练模型保存路径及文件
------out model/result.pkl 测试输出结果记录文件
测试结果如下:
以上就是mmdetection 在ubuntu16.04服务器上的配置详细过程和使用自己的数据集训练mmdetection faster_rcnn模型及测试的详细内容。
这个配置文件所描述的是基于resnet50的backbone,有5个fpn特征层的faster-RCNN目标检测网络,训练迭代次数为标准的12次epoch,下面逐条解释其含义
# model settings
model = dict(
type='FasterRCNN', # model类型
pretrained='modelzoo://resnet50', # 预训练模型:imagenet-resnet50
backbone=dict(
type='ResNet', # backbone类型
depth=50, # 网络层数
num_stages=4, # resnet的stage数量
out_indices=(0, 1, 2, 3), # 输出的stage的序号
frozen_stages=1, # 冻结的stage数量,即该stage不更新参数,-1表示所有的stage都更新参数
style='pytorch'), # 网络风格:如果设置pytorch,则stride为2的层是conv3x3的卷积层;如果设置caffe,则stride为2的层是第一个conv1x1的卷积层
neck=dict(
type='FPN', # neck类型
in_channels=[256, 512, 1024, 2048], # 输入的各个stage的通道数
out_channels=256, # 输出的特征层的通道数
num_outs=5), # 输出的特征层的数量
rpn_head=dict(
type='RPNHead', # RPN网络类型
in_channels=256, # RPN网络的输入通道数
feat_channels=256, # 特征层的通道数
anchor_scales=[8], # 生成的anchor的baselen,baselen = sqrt(w*h),w和h为anchor的宽和高
anchor_ratios=[0.5, 1.0, 2.0], # anchor的宽高比
anchor_strides=[4, 8, 16, 32, 64], # 在每个特征层上的anchor的步长(对应于原图)
target_means=[.0, .0, .0, .0], # 均值
target_stds=[1.0, 1.0, 1.0, 1.0], # 方差
use_sigmoid_cls=True), # 是否使用sigmoid来进行分类,如果False则使用softmax来分类
bbox_roi_extractor=dict(
type='SingleRoIExtractor', # RoIExtractor类型
roi_layer=dict(type='RoIAlign', out_size=7, sample_num=2), # ROI具体参数:ROI类型为ROIalign,输出尺寸为7,sample数为2
out_channels=256, # 输出通道数
featmap_strides=[4, 8, 16, 32]), # 特征图的步长
bbox_head=dict(
type='SharedFCBBoxHead', # 全连接层类型
num_fcs=2, # 全连接层数量
in_channels=256, # 输入通道数
fc_out_channels=1024, # 输出通道数
roi_feat_size=7, # ROI特征层尺寸
num_classes=81, # 分类器的类别数量+1,+1是因为多了一个背景的类别
target_means=[0., 0., 0., 0.], # 均值
target_stds=[0.1, 0.1, 0.2, 0.2], # 方差
reg_class_agnostic=False)) # 是否采用class_agnostic的方式来预测,class_agnostic表示输出bbox时只考虑其是否为前景,后续分类的时候再根据该bbox在网络中的类别得分来分类,也就是说一个框可以对应多个类别
# model training and testing settings
train_cfg = dict(
rpn=dict(
assigner=dict(
type='MaxIoUAssigner', # RPN网络的正负样本划分
pos_iou_thr=0.7, # 正样本的iou阈值
neg_iou_thr=0.3, # 负样本的iou阈值
min_pos_iou=0.3, # 正样本的iou最小值。如果assign给ground truth的anchors中最大的IOU低于0.3,则忽略所有的anchors,否则保留最大IOU的anchor
ignore_iof_thr=-1), # 忽略bbox的阈值,当ground truth中包含需要忽略的bbox时使用,-1表示不忽略
sampler=dict(
type='RandomSampler', # 正负样本提取器类型
num=256, # 需提取的正负样本数量
pos_fraction=0.5, # 正样本比例
neg_pos_ub=-1, # 最大负样本比例,大于该比例的负样本忽略,-1表示不忽略
add_gt_as_proposals=False), # 把ground truth加入proposal作为正样本
allowed_border=0, # 允许在bbox周围外扩一定的像素
pos_weight=-1, # 正样本权重,-1表示不改变原始的权重
smoothl1_beta=1 / 9.0, # 平滑L1系数
debug=False), # debug模式
rcnn=dict(
assigner=dict(
type='MaxIoUAssigner', # RCNN网络正负样本划分
pos_iou_thr=0.5, # 正样本的iou阈值
neg_iou_thr=0.5, # 负样本的iou阈值
min_pos_iou=0.5, # 正样本的iou最小值。如果assign给ground truth的anchors中最大的IOU低于0.3,则忽略所有的anchors,否则保留最大IOU的anchor
ignore_iof_thr=-1), # 忽略bbox的阈值,当ground truth中包含需要忽略的bbox时使用,-1表示不忽略
sampler=dict(
type='RandomSampler', # 正负样本提取器类型
num=512, # 需提取的正负样本数量
pos_fraction=0.25, # 正样本比例
neg_pos_ub=-1, # 最大负样本比例,大于该比例的负样本忽略,-1表示不忽略
add_gt_as_proposals=True), # 把ground truth加入proposal作为正样本
pos_weight=-1, # 正样本权重,-1表示不改变原始的权重
debug=False)) # debug模式
test_cfg = dict(
rpn=dict( # 推断时的RPN参数
nms_across_levels=False, # 在所有的fpn层内做nms
nms_pre=2000, # 在nms之前保留的的得分最高的proposal数量
nms_post=2000, # 在nms之后保留的的得分最高的proposal数量
max_num=2000, # 在后处理完成之后保留的proposal数量
nms_thr=0.7, # nms阈值
min_bbox_size=0), # 最小bbox尺寸
rcnn=dict(
score_thr=0.05, nms=dict(type='nms', iou_thr=0.5), max_per_img=100) # max_per_img表示最终输出的det bbox数量
# soft-nms is also supported for rcnn testing
# e.g., nms=dict(type='soft_nms', iou_thr=0.5, min_score=0.05) # soft_nms参数
)
# dataset settings
dataset_type = 'CocoDataset' # 数据集类型
data_root = 'data/coco/' # 数据集根目录
img_norm_cfg = dict(
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) # 输入图像初始化,减去均值mean并处以方差std,to_rgb表示将bgr转为rgb
data = dict(
imgs_per_gpu=2, # 每个gpu计算的图像数量
workers_per_gpu=2, # 每个gpu分配的线程数
train=dict(
type=dataset_type, # 数据集类型
ann_file=data_root + 'annotations/instances_train2017.json', # 数据集annotation路径
img_prefix=data_root + 'train2017/', # 数据集的图片路径
img_scale=(1333, 800), # 输入图像尺寸,最大边1333,最小边800
img_norm_cfg=img_norm_cfg, # 图像初始化参数
size_divisor=32, # 对图像进行resize时的最小单位,32表示所有的图像都会被resize成32的倍数
flip_ratio=0.5, # 图像的随机左右翻转的概率
with_mask=False, # 训练时附带mask
with_crowd=True, # 训练时附带difficult的样本
with_label=True), # 训练时附带label
val=dict(
type=dataset_type, # 同上
ann_file=data_root + 'annotations/instances_val2017.json', # 同上
img_prefix=data_root + 'val2017/', # 同上
img_scale=(1333, 800), # 同上
img_norm_cfg=img_norm_cfg, # 同上
size_divisor=32, # 同上
flip_ratio=0, # 同上
with_mask=False, # 同上
with_crowd=True, # 同上
with_label=True), # 同上
test=dict(
type=dataset_type, # 同上
ann_file=data_root + 'annotations/instances_val2017.json', # 同上
img_prefix=data_root + 'val2017/', # 同上
img_scale=(1333, 800), # 同上
img_norm_cfg=img_norm_cfg, # 同上
size_divisor=32, # 同上
flip_ratio=0, # 同上
with_mask=False, # 同上
with_label=False, # 同上
test_mode=True)) # 同上
# optimizer
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) # 优化参数,lr为学习率,momentum为动量因子,weight_decay为权重衰减因子
optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) # 梯度均衡参数
# learning policy
lr_config = dict(
policy='step', # 优化策略
warmup='linear', # 初始的学习率增加的策略,linear为线性增加
warmup_iters=500, # 在初始的500次迭代中学习率逐渐增加
warmup_ratio=1.0 / 3, # 起始的学习率
step=[8, 11]) # 在第8和11个epoch时降低学习率
checkpoint_config = dict(interval=1) # 每1个epoch存储一次模型
# yapf:disable
log_config = dict(
interval=50, # 每50个batch输出一次信息
hooks=[
dict(type='TextLoggerHook'), # 控制台输出信息的风格
# dict(type='TensorboardLoggerHook')
])
# yapf:enable
# runtime settings
total_epochs = 12 # 最大epoch数
dist_params = dict(backend='nccl') # 分布式参数
log_level = 'INFO' # 输出信息的完整度级别
work_dir = './work_dirs/faster_rcnn_r50_fpn_1x' # log文件和模型文件存储路径
load_from = None # 加载模型的路径,None表示从预训练模型加载
resume_from = None # 恢复训练模型的路径
workflow = [('train', 1)] # 当前工作区名称