detectron2的结构介绍
上一篇文章 detectron2的简介和配置_d948142375的博客-CSDN博客 介绍了怎么配置detectron2(以下简称DET2)到一台ubuntu18.04的远程服务器,本文将介绍为了实现一个基本的faster-RCNN该如何理解并运用DET2提供的功能。我不提供大量的代码讲解,DET2的代码、注释、doc非常的多,对于有基础的小伙伴,我只需要介绍其中最有价值的脚本及关键内容即可。你们仍然需要阅读我所提到的文件并理解其中的内容,所以本系列文章不适合直接co的人群。
DET2的colab
google提供了一个在线跑demo的环境colab:https://colab.research.google.com/drive/16jcaJoc6bCFAQ96jDe2HwtXj7BMD_-m5,并且google重构了一些功能例如cv2的imshow,所以在开始之前你需要先pip一下google-colab,不过colab google research的网站这几天崩了,网上说这个网站经常崩。我下载了这个网站的镜像,如有需要私信我。
最重要的是,colab提供了一套最基本的流程代码,可以跑起来那种,作为入门非常合适。但是镜像大约就只能看看代码了。
DET2的关键代码文件
如果需要自行配置一套模型并设计完整的流程,你需要仔细阅读下面所提到的文件,如果是初学者只打算跑完这个项目,下面几个文件可以跳过,内容比较多。
1. DET2的config是以树的形式存储的,detectron2/detectron2/config/defaults.py这个文件你需要认真看完,包含了算法细节的所有公共设置和各类衍生算法的改良设置,如果你懂图像识别的几种主流算法的话,这个文件的诸多设置英文名称你应当很熟悉,这个文件的注释也很全。所有简化的cfg最终都会继承自这里(不过简化cfg是先继承各自的default,然后继承自这里)。
从这个大而全的cfg文件(记为CFG)出发,可以在另一个目录:detectron2/configs/ 找到你需要的各种算法的default cfg和cfg文件,,其中子类cfg的第一行标明了它继承的父类cfg文件,创建项目所需的cfg文件需要先实例化一个cfg(get_cfg()),这一步继承自CFG,接下来需要merge一下所用算法的cfg。特别的,你需要根据CFG文件中所用算法的种类,修改不符合需求的默认设置。
值得注意的是,CFG文件有很多子类cfg没有的属性,你应该经常需要查看其中的属性,一定不要修改CFG原文件!
其中,主要的属性有这样几个关键字:MODEL(网络超参数),SOLVER(训练超参数),DATA/DATASET(数据集属性),按需查找,大多是默认设置好的。
当你所用算法的cfg属性配置完成,便可将cfg送到后续实例当中。值得注意的是,cfg.MODEL.ROI_HEADS.NUM_CLASSES应当直接是前景种类数量,而不包含背景。
2. DET2需要实例化一个训练器trainer,并向它送入cfg(DefaultTrainer(cfg)),在目录:detectron2/detectron2/engine/defaults.py,大致浏览即可。此外,还提供了预测器predictor在该文件中,用于简单地对给定图像进行预测。
3. DET2提供了可视化工具visualizer,不过远程调试需要配置xserver在远程地址输出,远程可视化日常用不到,跳过。
4. DET2提供了评估工具evaluator,在目录:detectron2/detectron2/evaluation 下,类似的,需要先实例化,提供了AP及其它维度的评估数据,DET2针对各种数据集,做了特定的评估工具。默认在训练结束后就进行评估,当你未实例化evaluator等之时,代码可能会报错。
5. DET2需要你提供标准数据集或是register一个标准风格的数据集才能使用各种功能,但是某些脚本注明仍适用结构一致的其它数据集。
6. DET2的注册数据集默认存放在./datasets目录下,而且应当有标准化的数据集存储格式,以Pascal VOC为例,用以下格式存放(默认格式):VOC20{07,12}.(Annotations, ImageSets.Main.(trainval.txt, test.txt), JPEGImages) 深度学习: VOC数据集详解(转载) - 简书 (jianshu.com),详见detectron2/datasets/README.md,有常见数据集的存放要求。
但是DET2需要注意的一点是,cfg.DATASETS.TRAIN=("VOC2007"),直接运行会报错未注册该数据集,因为注册数据集并不包含“VOC2007”字样,因为VOC2007所对应的是以下4种注册数据集:voc_2007_train, voc_2007_test, voc_2007_trainval, voc_2007_val,所以当你存放的是标准的VOC数据集时,更改cfg为:cfg.DATASETS.TRAIN=("voc_2007_train")(以此类推)。值得注意的是,你大约不能直接修改VOC的classname和img来替换VOC数据集的内容,因为DET2的metadata收集的是注册数据集的各种复用信息,且注册数据集的代码已经返回了一个字典,直接更改VOC数据集的内容将导致前后不一致而报错。类似于tf需要制record格式,DET2提供了各类标准数据集风格到DET2风格的转换方法,例如:./detectron2/data/datasets/pacal_voc.py,相似的还有其它数据集的转换方法,你需要阅读这份源码以了解它的arg和工作原理。阅读源码可以发现,需要分别注册train, test, val, tranval四个数据集,并返回一个大字典,这个大字典dict包含了所有(标签,图片)的字典"r"(类似json),"r"包含(file_name, image_id, height, width, annotations)几种属性,其中annotations又包含(category_id, bbox, bbox_mode)几种属性。
坑:
DET2是面向多来源数据集、多种类处理方法,所以在应用时直接代入对象名称(如字符串)会报错,往往报错的是“只读取了你录入字符串的首字母”,这是因为DET2大多数场合应当读取的是可迭代容器(如列表),所以当你报错“只读了你录入字符串的首字母”这类错误时,试试改成("input1",)转换成可迭代的tuple(注意逗号)。
与上一坑所对应的,当你出现读取字符串总是失败,类似读取成("input1",)的格式时,应当考虑改成input_tuple[0]获取tuple的字符串成员。
DET2默认的evaluator大多都是评估标准数据集(如VOC{2007,2012}的,所以当你使用客制化数据集时,只有两个evaluator可以使用:COCOEvaluator, SemSegEvaluator,其中COCOEvaluator应当输入已注册数据集的名字,或是json文件。其中COCOEvaluator实现了目标检测(bbox,如voc)、实例分割(segm)、关键点检测(keypoints)数据集自动转换成coco风格,前提是该数据集被正确register过。此外,这个evaluator提供的AP并不是标准AP算法,而是它的近似方法(为了更快,也占用了更多ram)。
以上register, cfg, trainer, evaluator,predictor以及datasets就构成了实现一个项目所需要的大致全部工具。
你应当常常需要register客制化数据集:
若你需要客制化一份数据集,那么你需要register一份DET2可以识别的数据集,DET2提供了一种有全局性质的数据集注册功能,被注册的数据集自注册起,将保留全局性并生存到流程终止。你可以按照以下标准重构你的数据集,或是添加新的属性,标准化的属性可以使用DET2的特性,但是新的属性的使用方法需要自己实现。
DET2的dataset register tutorial:Use Custom Datasets — detectron2 0.4 documentation 有需要设置的属性详细介绍
DET2的标准属性,自行阅读tutorial。
其中,值得注意的是,category_id是类别ID,最后一个ID指的是背景(如果有的话),但是你在cfg中填入的class number并不需要cls+1(背景),所以当你的类别ID出现问题,你应当优先考虑这两个问题:类别数量NUM_CLASSES是否少于实际类别数量,或是是否考虑“背景”类。此外,对于标签为空(但是有指向标签,即标签文件为空节点)等情况,默认将移出训练过程。对于custom dataset(即你添加其它属性的非标准数据集),是存储在内存中的,所以确保你的内存足够大,或者使用小数据集。
以上介绍了detectron2的核心模块,若你阅读了colab的demo,并阅读了以上我提及的脚本文件,那么你应当有能力搭建一套训练-评估-测试流程,以及制备detectron2风格的数据集。我也已经将训练-测试流程搭建完毕并成功跑了起来。
若我写的有误或有改良方法,望评论指出,谢谢。
实现代码,注册-训练-测试
其中,训练中自动调用evaluator进行评估并没有找到如何实现,我需要进一步实验,为了实现阶段性回滚,可以以例如10000轮迭代为周期,评估并保存报告和checkpoint,回滚时直接读对应checkpoint即可。
贴一下我的代码,本地化修改即可运行。
# -*- coding: utf-8 -*-
#!python==3.6
# @Time: 2021.06.22
# @Author: 蜗牛1515
# @url:detectron2的结构介绍及代码实现_d948142375的博客-CSDN博客
# @Software: pycharm -v2020.1.5
# key words: faster-RCNN, detectron2
# version: 0.3
import os
import random
import torch
import torchvision
import numpy as np
import json
import cv2
import detectron2
from detectron2.config import get_cfg
from detectron2 import model_zoo
from detectron2.data import build_detection_test_loader
from detectron2.data.datasets import load_voc_instances, register_pascal_voc
from detectron2.evaluation import COCOEvaluator, inference_on_dataset
from detectron2.utils.logger import setup_logger
from detectron2.engine import DefaultTrainer
from google.colab.patches import cv2_imshow
def my_register():
tag_dict = {
key:val,
...
}
dataset_name = name
year = year
class_name = tuple(tag_dict.keys())
for spt in ("train", "val", "trainval", "test"):
register_pascal_voc(name="%s_%s_%s"%(dataset_name, year, spt), dirname="./datasets/%s"%dataset_name,
split=spt, year=year, class_names=class_name)
print("register dataset:%s_%s_%s"%(dataset_name, year, spt), "successfully!")
def my_faster_RCNN():
# SEG: setup
cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file("Base-RCNN-FPN.yaml"))
cfg.merge_from_file(model_zoo.get_config_file("PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml"))
model_name = "faster_rcnn_R_50_FPN"
cfg.DATASETS.TRAIN = ('name_year_train',) #你register的数据集
cfg.DATASETS.TEST = ('name_year_test',)
cfg.MODEL.WEIGHTS = "net_weights_src/faster_R50_FPN.pkl"
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 22 # NOTE: this config means the number of classes
# but a few popular unofficial tutorials incorrect uses num_classes+1 here.
cfg.SOLVER.IMS_PER_BATCH = 4 # 一批的图,数量取决于显存
cfg.SOLVER.BASE_LR = 0.001
cfg.SOLVER.MAX_ITER = 100000
cfg.SOLVER.STEPS = [50000, 80000] # 学习率衰减区间
cfg.OUTPUT_DIR = "./output_%s"%model_name
# cfg.freeze()
# SEG: train
os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)
trainer = DefaultTrainer(cfg)
trainer.resume_or_load(resume=True) # 从断点继续训练,将忽略一开始读取的WEIGHTS,从最近的checkpoint进行训练。若为False,将忽略断点
trainer.train()
# SEG: test
cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, "model_final.pth") # path to the model we just trained
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.7 # set a custom testing threshold
evaluator = COCOEvaluator(
dataset_name=cfg.DATASETS.TEST[0], tasks=["bbox",], distributed=True,
output_dir=cfg.OUTPUT_DIR, use_fast_impl=True, kpt_oks_sigmas=()
) # dataset_name传入的应当是测试数据集名(字符串)而不是tuple,use_fast_impl指DET2自带的快速计算AP的近似方法
# test_loader = build_detection_test_loader(cfg, cfg.DATASETS.TEST)
trainer.test(cfg=cfg, model=trainer.model, evaluators=evaluator) # 将自动创建data_loader
# print(inference_on_dataset(trainer.model, test_loader, evaluator))
def main():
print("hello, detectron2!")
if __name__ == "__main__":
main()
my_register()
my_faster_RCNN()