1 前言
最近有研究和使用faster rcnn的需求,吸取之前的经验(数据并行化等坑),决定直接从高级框架入手。关于搭建的事项,坑比较多,可以参考本人之前的文章。本文从Detectron环境搭建完成并成功运行官方demo开始,
2 制作自己的数据集
2.1 准备数据
将数据放置到$DETECTRON/lib/datasets/data
(或其他目录下面再创建软连接),如ms_train数据集,并在其中以如下结构放置数据集的数据:
ms_train
├── annos.csv
├── annotations/
├── classes.txt
└── images/
其中,annos.csv是含BBox标注信息,每行对应一条BBOX标记:filename,label, x_min, y_min, x_max, y_max,如下
318818_002.png,31,237,313,261,327
318818_002.png,31,230,315,244,324
318818_005.png,31,200,180,246,205
318818_007.png,31,256,194,302,240
318818_007.png,31,262,358,289,378
318818_008.png,31,262,358,289,378
318818_009.png,31,262,358,289,378
annotations是空文件夹,准备拿来放生成的.json
文件
classes.txt说明本次任务的类别与其id,如下
5 apple
16 cat
images文件夹放置所有图片,文件名与上文的filename相同
2.2 转化标注格式
照着别人的实现和COCO官方数据集的声明,自己写了一份代码,跑通了。root_path换成你的实际地址
import json
import os
# import cv2
# 根路径,里面包含images(图片文件夹),annos.txt(bbox标注),classes.txt(类别标签),以及annotations文件夹(如果没有则会自动创建,用于保存最后的json)
root_path = '/media/zht/4945048867750FD1/CT/converted_to_coco/ms_train'
# 用于创建训练集或验证集
phase = 'train'
# 训练集和验证集划分的界线
split = 88000
# 初始化数据集信息
dataset = {
'licenses': [],
'info': {},
'categories': [],
'images': [],
'annotations': []
}
img_name_to_id = dict()
# 打开类别标签
with open(os.path.join(root_path, 'classes.txt')) as f:
classes = f.readlines()
# 建立类别标签和数字id的对应关系
for cls in classes:
cls_id, cls_name = cls.strip().split()
dataset['categories'].append({'id': int(cls_id), 'name': cls_name, 'supercategory': 'tumour'})
# 读取images文件夹的图片名称
indexes = [f for f in os.listdir(os.path.join(root_path, 'images'))]
_indexes = indexes.copy()
# 判断是建立训练集还是验证集
if phase == 'train':
indexes = [line for i, line in enumerate(_indexes) if i <= split]
elif phase == 'val':
indexes = [line for i, line in enumerate(_indexes) if i > split]
# 添加图像的信息到dataset中
for k, index in enumerate(indexes):
# 用opencv读取图片,得到图像的宽和高
# im = cv2.imread(os.path.join(root_path, 'images/') + index)
dataset['images'].append({'file_name': index,
'id': k,
'width': 512,
'height': 512})
img_name_to_id[index] = k
# 读取Bbox信息
with open(os.path.join(root_path, 'annos.csv')) as tr:
annos = tr.readlines()
for i, anno in enumerate(annos):
parts = anno.strip().split(',')
index = parts[0]
# 如果图像的名称和标记的名称对上,则添加标记
if index in img_name_to_id.keys():
# if parts[0] == index:
# 类别
cls_id = parts[1]
# x_min
x1 = float(parts[2])
# y_min
y1 = float(parts[3])
# x_max
x2 = float(parts[4])
# y_max
y2 = float(parts[5])
width = max(0, x2 - x1)
height = max(0, y2 - y1)
dataset['annotations'].append({
'area': width * height,
'bbox': [x1, y1, width, height],
'category_id': int(cls_id),
'id': i,
'image_id': img_name_to_id[index],
'iscrowd': 0,
# mask, 矩形是从左上角点按顺时针的四个顶点
'segmentation': [[x1, y1, x2, y1, x2, y2, x1, y2]]
})
# 保存结果的文件夹
folder = os.path.join(root_path, 'annotations')
if not os.path.exists(folder):
os.makedirs(folder)
json_name = os.path.join(root_path, 'annotations/{}.json'.format(phase))
with open(json_name, 'w') as f:
json.dump(dataset, f)
2.3 设置指向自己的数据集
至此,你的ms_train文件夹下已经有了.json
文件。COCO格式定义一个数据集,主要就是使用一个.json
,即,一个.json
+ 一个图片文件夹 ==> 一个COCO数据集。
修改$DETECTRON/lib/datasets/dataset_catalog.py
文件,照葫芦画瓢,添加自己的数据集(你也可以直接修改已有的数据集信息转向自己的数据集,但个人习惯不直接修改已有的):
'coco_2014_train': {
_IM_DIR:
_DATA_DIR + '/coco/coco_train2014',
_ANN_FN:
_DATA_DIR + '/coco/annotations/instances_train2014.json'
},
'coco_2014_val': {
_IM_DIR:
_DATA_DIR + '/coco/coco_val2014',
_ANN_FN:
_DATA_DIR + '/coco/annotations/instances_val2014.json'
},
'ms_train': {
_IM_DIR:
_DATA_DIR + '/ms_train/images',
_ANN_FN:
_DATA_DIR + '/ms_train/annotations/train.json'
},
'ms_val': {
_IM_DIR:
_DATA_DIR + '/ms_train/images',
_ANN_FN:
_DATA_DIR + '/ms_train/annotations/val.json'
},
3 新建配置文件,开始训练
到这里,设置好了相应的数据集,下面需要指定训练模型使用该数据集,Detectron是通过配置文件来指定的。
3.1 新建配置文件(.yaml)
根据你使用的GPU数量与要训练的网络模型,选择一个yaml配置文件;
可以直接复制Detectron自带的配置文件,并稍作修改即可,在$DETECTRON
根目录下复制:
cd configs
mkdir animals
cp getting_started/tutorial_1gpu_e2e_faster_rcnn_R-50-FPN.yaml animals/animals_1gpu_e2e_faster_rcnn_R-50-FPN.yaml
然后打开animals_1gpu_e2e_faster_rcnn_R-50-FPN.yaml进行编辑:
MODEL:
TYPE: generalized_rcnn
CONV_BODY: FPN.add_fpn_ResNet50_conv5_body
NUM_CLASSES: 5
FASTER_RCNN: True
NUM_GPUS: 1
SOLVER:
WEIGHT_DECAY: 0.0001
LR_POLICY: steps_with_decay
BASE_LR: 0.0025
GAMMA: 0.1
MAX_ITER: 60000
STEPS: [0, 30000, 40000]
# Equivalent schedules with...
# 1 GPU:
# BASE_LR: 0.0025
# MAX_ITER: 60000
# STEPS: [0, 30000, 40000]
# 2 GPUs:
# BASE_LR: 0.005
# MAX_ITER: 30000
# STEPS: [0, 15000, 20000]
# 4 GPUs:
# BASE_LR: 0.01
# MAX_ITER: 15000
# STEPS: [0, 7500, 10000]
# 8 GPUs:
# BASE_LR: 0.02
# MAX_ITER: 7500
# STEPS: [0, 3750, 5000]
RPN:
ASPECT_RATIOS: (0.5, 1, 2)
FPN:
FPN_ON: True
MULTILEVEL_ROIS: True
MULTILEVEL_RPN: True
RPN_ASPECT_RATIOS: (0.5, 1, 2)
FAST_RCNN:
ROI_BOX_HEAD: fast_rcnn_heads.add_roi_2mlp_head
ROI_XFORM_METHOD: RoIAlign
ROI_XFORM_RESOLUTION: 7
ROI_XFORM_SAMPLING_RATIO: 2
TRAIN:
WEIGHTS: pretrained_models/ImageNetPretrained/MSRA/R-50.pkl
DATASETS: ('ms_train',)
SCALES: (500,)
SNAPSHOT_ITERS: 5000
MAX_SIZE: 833
BATCH_SIZE_PER_IM: 256
RPN_PRE_NMS_TOP_N: 2000 # Per FPN level
TEST:
DATASETS: ('ms_val',)
SCALES: (500,)
MAX_SIZE: 833
NMS: 0.5
RPN_PRE_NMS_TOP_N: 1000 # Per FPN level
RPN_POST_NMS_TOP_N: 1000
FORCE_JSON_DATASET_EVAL: True
OUTPUT_DIR: .
主要修改以下内容:
- MODEL里的NUM_CLASSES,根据自己的数据集进行修改,包括背景。
2.T RAIN和TEST里的DATASETS,设置为如上所示,因为我们已经修改了dataset_catalog.py中的相应内容并指向了我们的数据集,所以我们可以直接使用这两个数据集的名字。 - TRAIN里的WEIGHTS是一个预训练的模型,如果本地有,修改指向它即可。
- 关于NUM_GPUS,这个需要与SOLVER里面的学习率等一干参数进行联动设置。
有个坑,在测试阶段,配置文件里要添加一条FORCE_JSON_DATASET_EVAL: True
,如下
TEST:
FORCE_JSON_DATASET_EVAL: True
3.2 开始训练
设置好数据集和配置文件,即可开始训练模型了。回到$DETECTRON
根目录,打开Terminal运行如下命令即可开始训练:
python tools/train_net.py --cfg configs/animals/animals_1gpu_e2e_faster_rcnn_R-50-FPN.yaml OUTPUT_DIR detectron-output
更多请参考官方文档
后记
第一次使用大型框架来做图像相关的任务,大概花了两天时间配置环境,然后又用了两天跑通自己的数据集,写下本文记录这个过程,转载请获得授权并注明本站信息
后续会研习相关paper并调整参数
参考
https://blog.csdn.net/qq_15969343/article/details/80848175
https://www.yueye.org/2018/train-object-detection-model-using-detectron.html
留言