前言:国庆的时间在网络上查找如何使用detectron2注册数据集,并使用了2位博主的相关代码,再次非常感谢2位博主的文章https://blog.csdn.net/qq_29750461,以及https://blog.csdn.net/weixin_39916966
对我的帮助和启发。
但目前大家写的方法都是直接在tools/train_net.py上直接添加相应的函数并且配置cfg的参数(这一部分可以在yaml中配置),因此我想的是如何直接在对应的python文件中修改对应部分的代码,使得train_net.py上不是那么冗余,使得添加的代码更加规范,并且进行下一步的修改会更加简单。
AdelaiDet可以算是Detectron2的一个扩展包,基本和Detectron2类似。
buildin.py
builtin_meta.py
由于detectron2中做detection的只有faster-rcnn,而AdelaiDet中含有了FCOS等比较新的模型,AdelaiDet中的FCOS是采用coco format,因此我需要将训练的pascalraw数据集从voc format 转化成 coco format。并且raw数据集只有3个class。
另外要特别说明的是,根据buildin.py文件中的COCO_CATEGORIES文件中的列表中展示的。 id都是从1开始的。因此在自己制作json文件时候,也要检查json中的catagories_id是不是从1开始的。
安装好detectron2或AdelaiDet。或者至少熟悉了detectron2或AdelaiDet的INSTALL.md和GETTING_STARTED.md以及datasets/readme.md如何Use Builtin Datasets
借用之前博主的言语,只要熟悉了这几个函数,基本就能够明白注册的流程了。
data/datasets/buildin.py/register_all_coco(root="datasets")
data/datasets/buildin_meta.py/_get_builtin_metadata(dataset_name)
data/datasets/buildin_meta.py/_get_coco_instances_meta()
data/datasets/register_coco.py/register_coco_instances(name, metadata, json_file, image_root)
data/datasets/coco.py/load_coco_json(json_file, image_root, dataset_name=None, extra_annotation_keys=None)
coco/
annotations/
instances_{
train,val}2017.json
person_keypoints_{
train,val}2017.json
{
train,val}2017/
# image files that are mentioned in the corresponding json
_PREDEFINED_SPLITS_COCO = {
}
_PREDEFINED_SPLITS_COCO["coco"] = {
"coco_2014_train": ("coco/train2014", "coco/annotations/instances_train2014.json"),
"coco_2014_val": ("coco/val2014", "coco/annotations/instances_val2014.json"),
"coco_2014_minival": ("coco/val2014", "coco/annotations/instances_minival2014.json"),
"coco_2014_minival_100": ("coco/val2014", "coco/annotations/instances_minival2014_100.json"),
"coco_2014_valminusminival": (
"coco/val2014",
"coco/annotations/instances_valminusminival2014.json",
),
"coco_2017_train": ("coco/train2017", "coco/annotations/instances_train2017.json"),
"coco_2017_val": ("coco/val2017", "coco/annotations/instances_val2017.json"),
"coco_2017_test": ("coco/test2017", "coco/annotations/image_info_test2017.json"),
"coco_2017_test-dev": ("coco/test2017", "coco/annotations/image_info_test-dev2017.json"),
"coco_2017_val_100": ("coco/val2017", "coco/annotations/instances_val2017_100.json"),
#我新注册的数据集,注意路径别写错了,以及注册的名字如coco_raw_train别写错了。
"coco_raw_train": ("coco_raw/train2017", "coco_raw/annotations/raw_train.json"),
"coco_raw_val": ("coco_raw/val2017", "coco_raw/annotations/raw_val.json"),
#"coco_raw_frcnn_train": ("coco_raw/train2017", "coco_raw/annotations/raw_train.json"),
#"coco_raw_frcnn_val": ("coco_raw/val2017", "coco_raw/annotations/raw_val.json"),
}
在这里面还调用了_get_builtin_metadata(dataset_name)以及register_coco_instances()这2个函数
def register_all_coco(root): #first step
for dataset_name, splits_per_dataset in _PREDEFINED_SPLITS_COCO.items():
for key, (image_root, json_file) in splits_per_dataset.items():
# Assume pre-defined datasets live in `./datasets`.
# print('detectron2:', key, (image_root, json_file))
register_coco_instances( #second step
key,
_get_builtin_metadata(dataset_name), #third step
os.path.join(root, json_file) if "://" not in json_file else json_file,
os.path.join(root, image_root),
)
def _get_builtin_metadata(dataset_name):
if dataset_name == "coco":
return _get_coco_instances_meta() #如果是coco 进入_get_coco_instances_meta()_get_coco_instances_meta()函数
if dataset_name == "coco_panoptic_separated":
return _get_coco_panoptic_separated_meta()
elif dataset_name == "coco_person":
return {
"thing_classes": ["person"],
"keypoint_names": COCO_PERSON_KEYPOINT_NAMES,
"keypoint_flip_map": COCO_PERSON_KEYPOINT_FLIP_MAP,
"keypoint_connection_rules": KEYPOINT_CONNECTION_RULES,
}
COCO_CATEGORIES = [
{
"color": [220, 20, 60], "isthing": 1, "id": 1, "name": "person"},
{
"color": [119, 11, 32], "isthing": 1, "id": 2, "name": "bicycle"},
{
"color": [0, 0, 142], "isthing": 1, "id": 3, "name": "car"},
{
"color": [0, 0, 230], "isthing": 1, "id": 4, "name": "motorcycle"},
{
"color": [106, 0, 228], "isthing": 1, "id": 5, "name": "airplane"},
{
"color": [0, 60, 100], "isthing": 1, "id": 6, "name": "bus"},
{
"color": [0, 80, 100], "isthing": 1, "id": 7, "name": "train"},
{
"color": [0, 0, 70], "isthing": 1, "id": 8, "name": "truck"},
{
"color": [0, 0, 192], "isthing": 1, "id": 9, "name": "boat"},
##省略
]
# 仿造制作数据集 注意此处的id(我不知道0开始如何) 以及name 必须必须要和json_file相对应,需要认真检查。
COCO_CATEGORIES_raw = [
{
"color": [119, 11, 32], "isthing": 1, "id": 1, "name": "bicycle"},
{
"color": [0, 0, 142], "isthing": 1, "id": 2, "name": "car"},
{
"color": [220, 20, 60], "isthing": 1, "id": 3, "name": "person"},
]
#注意: 可以在原来的基础之上进行修改,这里我把原来的COCO_CATEGORIES改成了我使用的 标注列表COCO_CATEGORIES_raw 改成你们自己的就好~
def _get_coco_instances_meta():
thing_ids = [k["id"] for k in COCO_CATEGORIES_raw if k["isthing"] == 1]
thing_colors = [k["color"] for k in COCO_CATEGORIES_raw if k["isthing"] == 1]
assert len(thing_ids) == 3, len(thing_ids)
# Mapping from the incontiguous COCO category id to an id in [0, 79]
thing_dataset_id_to_contiguous_id = {
k: i for i, k in enumerate(thing_ids)}
thing_classes = [k["name"] for k in COCO_CATEGORIES_raw if k["isthing"] == 1]
#print("_get_coco_instances_meta thing_classes:", thing_classes)
'''
_get_coco_instances_meta thing_classes: ['bicycle', 'car', 'person']
'''
ret = {
"thing_dataset_id_to_contiguous_id": thing_dataset_id_to_contiguous_id,
"thing_classes": thing_classes,
"thing_colors": thing_colors,
}
print("ret:", ret)
'''
ret = {'thing_dataset_id_to_contiguous_id': {1: 0, 2: 1, 3: 2}, 'thing_classes': ['bicycle', 'car', 'person'], 'thing_colors': [[119, 11, 32], [0, 0, 142], [220, 20, 60]]}
'''
return ret
师兄和我讲过很精辟的总结,把参数yaml文件看成是一直json文件。
例如cfg.MODEL.FCOS.NUM_CLASSES就可以在对应的yaml文件写成:
1. MODEL:
FCOS:
NUM_CLASSES: 80
其实就是空2格的一种结构。detectron2使用这种yaml文件是非常方便你就不用写这么多了这么多了。
只要设置好对应的–config-file 配置yaml文件就好。
另外yaml文件是继承与覆盖的关系。如果要修改yaml文件。记得看清楚特殊的就在子类上修改。建议练手之前先copy一份。
#由Base-FCOS.yaml修改的Base-FCOS_raw.yaml
MODEL:
META_ARCHITECTURE: "OneStageDetector"
BACKBONE:
NAME: "build_fcos_resnet_fpn_backbone"
RESNETS:
OUT_FEATURES: ["res3", "res4", "res5"]
FPN:
IN_FEATURES: ["res3", "res4", "res5"]
PROPOSAL_GENERATOR:
NAME: "FCOS"
# PIXEL_MEAN: [102.9801, 115.9465, 122.7717]
FCOS:
NUM_CLASSES: 3
DATASETS:
TRAIN: ("coco_raw_train",) #your_dataset_train
TEST: ("coco_raw_val",)#your_dataset_val
SOLVER:
IMS_PER_BATCH: 8
BASE_LR: 0.01 # Note that RetinaNet uses a different default learning rate
STEPS: (7000, 9000) #在steps步后按照CFG.SOLVER.GAMMA降低学习率
MAX_ITER: 11900 #MAX_ITER = epoch * image_train_total_nums / IMS_PER_BATCH
CHECKPOINT_PERIOD: 425 #save XX.pth文件 per EVAL_PERIOD
#MAX_ITER: 90000
INPUT:
#MIN_SIZE_TRAIN: (640, 672, 704, 736, 768, 800)
MIN_SIZE_TRAIN: (400, 600)
MIN_SIZE_TEST: 400
TEST:
EVAL_PERIOD: 850 #eval
#由R_50_1x.yaml 修改后的文件R_50_1x_raw.yaml
_BASE_: "Base-FCOS_raw.yaml" #继承Base-FCOS.yaml
MODEL:
WEIGHTS: "detectron2://ImageNetPretrained/MSRA/R-50.pkl" # pre-trained model
FCOS: #MODEL.FCOS
NUM_CLASSES: 3 #MODEL.FCOS.NUM_CLASSES
RESNETS:
DEPTH: 50
INPUT:
MIN_SIZE_TRAIN: (400, 600)
OUTPUT_DIR: "output/fcos/R_50_1x" # your output_dir 也可以手动在命令行中设置。
cd demo/
python demo.py --config-file ../configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml \
--input input1.jpg input2.jpg \
[--other-options]
--opts MODEL.WEIGHTS detectron2://COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x/137849600/model_final_f10217.pkl
这周大部分时间在学习如何使用AdelaiDet子框架来训练自己的数据集。由于AdelaiDet是类似detectron2的扩展框架,有些地方比较麻烦,并且上周的class对应不正确问题,导致卡壳了很久,这一整周又踩了许多坑,例如修改的json文件出错,训练不匹配,可视化后的图片没有class标签等等。
最后非常感谢多个师兄在这一周多的时间对我的帮助,亲手指导,点拨了我很多等等。从一开始摘抄博客中相应的冗余的代码进行训练,却不知其所以然,到后来能够使用相应的配置文件,直接在对应的注册数据集文件中修改对应的代码,进行修改添加,深感自己debug水平,阅读代码水平之差,需要继续完成下一步的操作。
因此将整个过程整理一下,方便后续的操作,也希望能够让其他人少走一点弯路。