Bootstrap

【Detectron2】使用 Detectron2 训练基于 coco 数据集的目标检测网络

一、安装 Detectron2

初次接触 Detectron2 的话,可能安装会遇到些坑,大家可以按下面的方式逐步安装,基本不会有什么问题。如果用到别的数据库的话,安装对应的api就可以。

# 使用 conda 创建虚拟环境
conda create -n detectron2 python=3.7
# 激活虚拟环境
conda activate detectron2
# 安装pytorch,注意对应的 cuda
conda install pytorch=1.6 torchvision cudatoolkit=10.2 -c pytorch
conda install opencv-python
pip install cython
# 安装cocopai
https://github.com/cocodataset/cocoapi.git
cd cocoapi/PythonAPI/
make
python setup.py install --user
cd ../../
# 安装 DCNv2
git clone https://github.com/CharlesShang/DCNv2.git
cd DCNv2
export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
./make.sh
# 克隆detectron2包,并安装
git clone https://github.com/facebookresearch/detectron2.git
python setup.py build develop
pip install -e .

二、软连接 coco 数据集

克隆下来的 detectron2 是下面的结构,为了不混淆,我自己命名成了 detectron2_test:

在这里插入图片描述
如果不想在 coco.py 中修改文件路径的话,可以把现有的 coco 数据集软连接到 detectron2_test/detectron2/data/datasets/ 中即可:

$ cd detectron2_test/detectron2/data/datasets/
$ ln -s xxx/coco .

三、训练

$ pwd
detectron2_test
$ ./tools/train_net.py --config-file configs/COCO-Detection/faster_rcnn_R_50_C4_1x.yaml

四、数据集相关参数

数据集的相关参数是模型训练的很重要的一部分,如果需要训练自己的数据集的话,需要在下面的三个文件中,修改成自己数据集中对应的类别个数、类别名称和 json 路径等。

# 1
detectron2_test/detectron2/data/datasets/coco.py

在这里插入图片描述

# 2
detectron2_test/detectron2/data/datasets/builtin.py

在这里插入图片描述

# 3
detectron2_test/detectron2/data/datasets/builtin_meta.py

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
coco 数据集介绍:

coco 数据集每个类别数量:

在这里插入图片描述

五、输出结果路径

detectron2_test/configs/defaults.py

六、COCO 数据集简介

COCO 数据集下载:

wget http://images.cocodataset.org/zips/train2017.zip
wget http://images.cocodataset.org/zips/val2017.zip
wget http://images.cocodataset.org/zips/test2017.zip
wget http://images.cocodataset.org/annotations/annotations_trainval2017.zip

coco 数据集的结构如下,共由5个关键字段构成,每个字段的内容如下面代码打印所示:

  • info
  • licenses
  • images
  • annotations
  • categories
file = io.open('instances_val2017.json', 'r', encoding='utf-8')
content = json.load(file)
print(content.keys())
>>>
dict_keys(['info', 'licenses', 'images', 'annotations', 'categories'])
print(content['info'])
>>>
{'description': 'COCO 2017 Dataset', 'url': 'http://cocodataset.org', 'version': '1.0', 'year': 2017, 'contributor': 'COCO Consortium', 'date_created': '2017/09/01'}
print(content['licenses'])
>>>[
{'url': 'http://creativecommons.org/licenses/by-nc-sa/2.0/', 'id': 1, 'name': 'Attribution-NonCommercial-ShareAlike License'}, 
{'url': 'http://creativecommons.org/licenses/by-nc/2.0/', 'id': 2, 'name': 'Attribution-NonCommercial License'}, 
{'url': 'http://creativecommons.org/licenses/by-nc-nd/2.0/', 'id': 3, 'name': 'Attribution-NonCommercial-NoDerivs License'}, 
{'url': 'http://creativecommons.org/licenses/by/2.0/', 'id': 4, 'name': 'Attribution License'}, 
{'url': 'http://creativecommons.org/licenses/by-sa/2.0/', 'id': 5, 'name': 'Attribution-ShareAlike License'}, 
{'url': 'http://creativecommons.org/licenses/by-nd/2.0/', 'id': 6, 'name': 'Attribution-NoDerivs License'}, 
{'url': 'http://flickr.com/commons/usage/', 'id': 7, 'name': 'No known copyright restrictions'}, 
{'url': 'http://www.usa.gov/copyright.shtml', 'id': 8, 'name': 'United States Government Work'}]
print(content['images'])
>>>[
{'license': 1, 'file_name': '000000548246.jpg', 'coco_url': 'http://images.cocodataset.org/val2017/000000548246.jpg', 'height': 428, 'width': 640, 'date_captured': '2013-11-23 03:52:52', 'flickr_url': 'http://farm4.staticflickr.com/3115/2905881071_5b16058d7b_z.jpg', 'id': 548246}, ...]
print(content['annotations'][0]) # type = list, len(content['annotations'])=36781
>>>{
'segmentation': [[510.66, 423.01, 511.72, 420.03, 510.45, 416.0, 510.34, 413.02, 510.77, 410.26, 510.77, 407.5, 510.34, 405.16, 511.51, 402.83, 511.41, 400.49, 510.24, 398.16, 509.39, 397.31, 504.61, 399.22, 502.17, 399.64, 500.89, 401.66, 500.47, 402.08, 499.09, 401.87, 495.79, 401.98, 490.59, 401.77, 488.79, 401.77, 485.39, 398.58, 483.9, 397.31, 481.56, 396.35, 478.48, 395.93, 476.68, 396.03, 475.4, 396.77, 473.92, 398.79, 473.28, 399.96, 473.49, 401.87, 474.56, 403.47, 473.07, 405.59, 473.39, 407.71, 476.68, 409.41, 479.23, 409.73, 481.56, 410.69, 480.4, 411.85, 481.35, 414.93, 479.86, 418.65, 477.32, 420.03, 476.04, 422.58, 479.02, 422.58, 480.29, 423.01, 483.79, 419.93, 486.66, 416.21, 490.06, 415.57, 492.18, 416.85, 491.65, 420.24, 492.82, 422.9, 493.56, 424.39, 496.43, 424.6, 498.02, 423.01, 498.13, 421.31, 497.07, 420.03, 497.07, 415.15, 496.33, 414.51, 501.1, 411.96, 502.06, 411.32, 503.02, 415.04, 503.33, 418.12, 501.1, 420.24, 498.98, 421.63, 500.47, 424.39, 505.03, 423.32, 506.2, 421.31, 507.69, 419.5, 506.31, 423.32, 510.03, 423.01, 510.45, 423.01]], 
'area': 702.1057499999998, 
'iscrowd': 0, 
'image_id': 289343, 
'bbox': [473.07, 395.93, 38.65, 28.67], 
'category_id': 18, 
'id': 1768}
print(content['categories']) # len(content['categories']=80)
>>>[
{'supercategory': 'person', 'id': 1, 'name': 'person'}, 
{'supercategory': 'vehicle', 'id': 2, 'name': 'bicycle'}, 
{'supercategory': 'vehicle', 'id': 3, 'name': 'car'}, 
{'supercategory': 'vehicle', 'id': 4, 'name': 'motorcycle'}, 
{'supercategory': 'vehicle', 'id': 5, 'name': 'airplane'}, 
{'supercategory': 'vehicle', 'id': 6, 'name': 'bus'}, 
{'supercategory': 'vehicle', 'id': 7, 'name': 'train'}, 
{'supercategory': 'vehicle', 'id': 8, 'name': 'truck'}, 
{'supercategory': 'vehicle', 'id': 9, 'name': 'boat'}, 
{'supercategory': 'outdoor', 'id': 10, 'name': 'traffic light'}, 
{'supercategory': 'outdoor', 'id': 11, 'name': 'fire hydrant'}, 
{'supercategory': 'outdoor', 'id': 13, 'name': 'stop sign'}, 
{'supercategory': 'outdoor', 'id': 14, 'name': 'parking meter'}, 
{'supercategory': 'outdoor', 'id': 15, 'name': 'bench'}, 
{'supercategory': 'animal', 'id': 16, 'name': 'bird'}, 
{'supercategory': 'animal', 'id': 17, 'name': 'cat'}, 
{'supercategory': 'animal', 'id': 18, 'name': 'dog'}, 
{'supercategory': 'animal', 'id': 19, 'name': 'horse'}, 
{'supercategory': 'animal', 'id': 20, 'name': 'sheep'}, 
{'supercategory': 'animal', 'id': 21, 'name': 'cow'}, 
{'supercategory': 'animal', 'id': 22, 'name': 'elephant'}, 
{'supercategory': 'animal', 'id': 23, 'name': 'bear'}, 
{'supercategory': 'animal', 'id': 24, 'name': 'zebra'}, 
{'supercategory': 'animal', 'id': 25, 'name': 'giraffe'}, 
{'supercategory': 'accessory', 'id': 27, 'name': 'backpack'}, 
{'supercategory': 'accessory', 'id': 28, 'name': 'umbrella'}, 
{'supercategory': 'accessory', 'id': 31, 'name': 'handbag'}, 
{'supercategory': 'accessory', 'id': 32, 'name': 'tie'}, 
{'supercategory': 'accessory', 'id': 33, 'name': 'suitcase'}, 
{'supercategory': 'sports', 'id': 34, 'name': 'frisbee'}, 
{'supercategory': 'sports', 'id': 35, 'name': 'skis'}, 
{'supercategory': 'sports', 'id': 36, 'name': 'snowboard'}, 
{'supercategory': 'sports', 'id': 37, 'name': 'sports ball'}, 
{'supercategory': 'sports', 'id': 38, 'name': 'kite'}, 
{'supercategory': 'sports', 'id': 39, 'name': 'baseball bat'}, 
{'supercategory': 'sports', 'id': 40, 'name': 'baseball glove'}, 
{'supercategory': 'sports', 'id': 41, 'name': 'skateboard'}, 
{'supercategory': 'sports', 'id': 42, 'name': 'surfboard'}, 
{'supercategory': 'sports', 'id': 43, 'name': 'tennis racket'}, 
{'supercategory': 'kitchen', 'id': 44, 'name': 'bottle'}, 
{'supercategory': 'kitchen', 'id': 46, 'name': 'wine glass'}, 
{'supercategory': 'kitchen', 'id': 47, 'name': 'cup'},
{'supercategory': 'kitchen', 'id': 48, 'name': 'fork'}, 
{'supercategory': 'kitchen', 'id': 49, 'name': 'knife'}, 
{'supercategory': 'kitchen', 'id': 50, 'name': 'spoon'}, 
{'supercategory': 'kitchen', 'id': 51, 'name': 'bowl'}, 
{'supercategory': 'food', 'id': 52, 'name': 'banana'}, 
{'supercategory': 'food', 'id': 53, 'name': 'apple'}, 
{'supercategory': 'food', 'id': 54, 'name': 'sandwich'},
{'supercategory': 'food', 'id': 55, 'name': 'orange'}, 
{'supercategory': 'food', 'id': 56, 'name': 'broccoli'}, 
{'supercategory': 'food', 'id': 57, 'name': 'carrot'}, 
{'supercategory': 'food', 'id': 58, 'name': 'hot dog'}, 
{'supercategory': 'food', 'id': 59, 'name': 'pizza'}, 
{'supercategory': 'food', 'id': 60, 'name': 'donut'}, 
{'supercategory': 'food', 'id': 61, 'name': 'cake'}, 
{'supercategory': 'furniture', 'id': 62, 'name': 'chair'}, 
{'supercategory': 'furniture', 'id': 63, 'name': 'couch'},
{'supercategory': 'furniture', 'id': 64, 'name': 'potted plant'}, 
{'supercategory': 'furniture', 'id': 65, 'name': 'bed'}, 
{'supercategory': 'furniture', 'id': 67, 'name': 'dining table'}, 
{'supercategory': 'furniture', 'id': 70, 'name': 'toilet'}, 
{'supercategory': 'electronic', 'id': 72, 'name': 'tv'}, 
{'supercategory': 'electronic', 'id': 73, 'name': 'laptop'}, 
{'supercategory': 'electronic', 'id': 74, 'name': 'mouse'},   
{'supercategory': 'electronic', 'id': 75, 'name': 'remote'}, 
{'supercategory': 'electronic', 'id': 76, 'name': 'keyboard'},
{'supercategory': 'electronic', 'id': 77, 'name': 'cell phone'},
{'supercategory': 'appliance', 'id': 78, 'name': 'microwave'}, 
{'supercategory': 'appliance', 'id': 79, 'name': 'oven'}, 
{'supercategory': 'appliance', 'id': 80, 'name': 'toaster'}, 
{'supercategory': 'appliance', 'id': 81, 'name': 'sink'}, 
{'supercategory': 'appliance', 'id': 82, 'name': 'refrigerator'}, 
{'supercategory': 'indoor', 'id': 84, 'name': 'book'}, 
{'supercategory': 'indoor', 'id': 85, 'name': 'clock'}, 
{'supercategory': 'indoor', 'id': 86, 'name': 'vase'}, 
{'supercategory': 'indoor', 'id': 87, 'name': 'scissors'}, 
{'supercategory': 'indoor', 'id': 88, 'name': 'teddy bear'}, 
{'supercategory': 'indoor', 'id': 89, 'name': 'hair drier'},
{'supercategory': 'indoor', 'id': 90, 'name': 'toothbrush'}]

七、模型相关参数

MODEL:
  META_ARCHITECTURE: "GeneralizedRCNN"
  BACKBONE:
    NAME: "build_resnet_fpn_backbone"
  RESNETS:
    OUT_FEATURES: ["res2", "res3", "res4", "res5"]
  FPN:
    IN_FEATURES: ["res2", "res3", "res4", "res5"]
  ANCHOR_GENERATOR:
    SIZES: [[32], [64], [128], [256], [512]]  # One size for each in feature map
    ASPECT_RATIOS: [[0.5, 1.0, 2.0]]  # Three aspect ratios (same for all in feature maps)
  RPN:
    IN_FEATURES: ["p2", "p3", "p4", "p5", "p6"]
    PRE_NMS_TOPK_TRAIN: 2000  # Per FPN level
    PRE_NMS_TOPK_TEST: 1000  # Per FPN level
    # Detectron1 uses 2000 proposals per-batch,
    # (See "modeling/rpn/rpn_outputs.py" for details of this legacy issue)
    # which is approximately 1000 proposals per-image since the default batch size for FPN is 2.
    POST_NMS_TOPK_TRAIN: 1000
    POST_NMS_TOPK_TEST: 1000
  ROI_HEADS:
    NAME: "StandardROIHeads"
    IN_FEATURES: ["p2", "p3", "p4", "p5"]
  ROI_BOX_HEAD:
    NAME: "FastRCNNConvFCHead"
    NUM_FC: 2
    POOLER_RESOLUTION: 7
  ROI_MASK_HEAD:
    NAME: "MaskRCNNConvUpsampleHead"
    NUM_CONV: 4
    POOLER_RESOLUTION: 14
DATASETS:
  TRAIN: ("coco_2017_train",)
  TEST: ("coco_2017_val",)
SOLVER:
  IMS_PER_BATCH: 16
  BASE_LR: 0.02
  STEPS: (60000, 80000)
  MAX_ITER: 90000
INPUT:
  MIN_SIZE_TRAIN: (640, 672, 704, 736, 768, 800)
VERSION: 2

八、可视化结果

demo/demo.py
python demo/demo.py --config-file configs/COCO-Detection/faster_rcnn_R_50_FPN_1x.yaml --input /mnt/nfs-storage/train_data/coco/val2017/*.jpg   --output coco_val_test --opt MODEL.WEIGHTS output/model_0049999.pth

如果类别不是coco的80类的话,需要修改下面两个地方为自己的类别数量:

detectron2_test/detectron2/configs/default.py

在这里插入图片描述
在这里插入图片描述

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;