From d23da204620162f2e4b04a9a7d0145051a8b13cc Mon Sep 17 00:00:00 2001 From: Sharpiless <1691608003@qq.com> Date: Mon, 18 Apr 2022 10:26:59 +0800 Subject: [PATCH] first commit --- CITATION.cff | 8 + LICENSE | 203 ++ MANIFEST.in | 6 + README.md | 75 + README_zh-CN.md | 14 + .../_base_/datasets/cityscapes_detection.py | 56 + .../_base_/datasets/cityscapes_instance.py | 56 + configs/_base_/datasets/coco_detection.py | 49 + .../_base_/datasets/coco_detection_pix2seq.py | 68 + .../_base_/datasets/coco_detection_vqvae.py | 69 + configs/_base_/datasets/coco_instance.py | 49 + .../_base_/datasets/coco_instance_semantic.py | 54 + configs/_base_/datasets/coco_panoptic.py | 59 + configs/_base_/datasets/deepfashion.py | 53 + configs/_base_/datasets/lvis_v0.5_instance.py | 24 + configs/_base_/datasets/lvis_v1_instance.py | 24 + configs/_base_/datasets/voc0712.py | 55 + configs/_base_/datasets/voc0712_pix2seq.py | 73 + configs/_base_/datasets/wider_face.py | 63 + configs/_base_/default_runtime.py | 16 + .../models/cascade_mask_rcnn_r50_fpn.py | 196 ++ configs/_base_/models/cascade_rcnn_r50_fpn.py | 179 + configs/_base_/models/fast_rcnn_r50_fpn.py | 62 + .../_base_/models/faster_rcnn_r50_caffe_c4.py | 114 + .../models/faster_rcnn_r50_caffe_dc5.py | 105 + configs/_base_/models/faster_rcnn_r50_fpn.py | 108 + .../_base_/models/mask_rcnn_r50_caffe_c4.py | 125 + configs/_base_/models/mask_rcnn_r50_fpn.py | 120 + configs/_base_/models/retinanet_r50_fpn.py | 60 + configs/_base_/models/rpn_r50_caffe_c4.py | 58 + configs/_base_/models/rpn_r50_fpn.py | 58 + configs/_base_/models/ssd300.py | 56 + configs/_base_/schedules/schedule_1x.py | 11 + configs/_base_/schedules/schedule_20e.py | 11 + configs/_base_/schedules/schedule_2x.py | 11 + configs/albu_example/README.md | 19 + .../mask_rcnn_r50_fpn_albu_1x_coco.py | 73 + configs/atss/README.md | 21 + configs/atss/atss_r101_fpn_1x_coco.py | 6 + configs/atss/atss_r50_fpn_1x_coco.py | 62 + configs/atss/metafile.yml | 60 + configs/autoassign/README.md | 25 + .../autoassign_r50_fpn_8x2_1x_coco.py | 85 + configs/autoassign/metafile.yml | 33 + configs/carafe/README.md | 32 + .../faster_rcnn_r50_fpn_carafe_1x_coco.py | 50 + .../mask_rcnn_r50_fpn_carafe_1x_coco.py | 60 + configs/cascade_rcnn/README.md | 69 + ...ascade_mask_rcnn_r101_caffe_fpn_1x_coco.py | 7 + ...ask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py | 7 + .../cascade_mask_rcnn_r101_fpn_1x_coco.py | 6 + .../cascade_mask_rcnn_r101_fpn_20e_coco.py | 6 + ...cade_mask_rcnn_r101_fpn_mstrain_3x_coco.py | 6 + ...cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py | 41 + ...mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py | 49 + .../cascade_mask_rcnn_r50_fpn_1x_coco.py | 5 + .../cascade_mask_rcnn_r50_fpn_20e_coco.py | 5 + ...scade_mask_rcnn_r50_fpn_mstrain_3x_coco.py | 4 + ...ascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py | 14 + ...scade_mask_rcnn_x101_32x4d_fpn_20e_coco.py | 14 + ...ask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py | 14 + ...ask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py | 60 + ...ascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py | 14 + ...scade_mask_rcnn_x101_64x4d_fpn_20e_coco.py | 14 + ...ask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py | 14 + .../cascade_rcnn_r101_caffe_fpn_1x_coco.py | 7 + .../cascade_rcnn_r101_fpn_1x_coco.py | 6 + .../cascade_rcnn_r101_fpn_20e_coco.py | 6 + .../cascade_rcnn_r50_caffe_fpn_1x_coco.py | 42 + .../cascade_rcnn_r50_fpn_1x_coco.py | 5 + .../cascade_rcnn_r50_fpn_20e_coco.py | 4 + .../cascade_rcnn_x101_32x4d_fpn_1x_coco.py | 14 + .../cascade_rcnn_x101_32x4d_fpn_20e_coco.py | 14 + .../cascade_rcnn_x101_64x4d_fpn_1x_coco.py | 15 + .../cascade_rcnn_x101_64x4d_fpn_20e_coco.py | 15 + configs/cascade_rcnn/metafile.yml | 525 +++ configs/cascade_rpn/README.md | 29 + .../crpn_fast_rcnn_r50_caffe_fpn_1x_coco.py | 77 + .../crpn_faster_rcnn_r50_caffe_fpn_1x_coco.py | 92 + .../cascade_rpn/crpn_r50_caffe_fpn_1x_coco.py | 77 + configs/centernet/README.md | 30 + .../centernet/centernet_resnet18_140e_coco.py | 3 + .../centernet_resnet18_dcnv2_140e_coco.py | 122 + configs/centernet/metafile.yml | 46 + configs/centripetalnet/README.md | 26 + ...lnet_hourglass104_mstest_16x6_210e_coco.py | 105 + configs/centripetalnet/metafile.yml | 39 + configs/cityscapes/README.md | 33 + .../faster_rcnn_r50_fpn_1x_cityscapes.py | 39 + .../mask_rcnn_r50_fpn_1x_cityscapes.py | 46 + configs/common/lsj_100e_coco_instance.py | 90 + .../common/mstrain-poly_3x_coco_instance.py | 80 + configs/common/mstrain_3x_coco.py | 76 + configs/common/mstrain_3x_coco_instance.py | 76 + configs/cornernet/README.md | 33 + ...rnet_hourglass104_mstest_10x5_210e_coco.py | 105 + ...rnet_hourglass104_mstest_32x3_210e_coco.py | 105 + ...ernet_hourglass104_mstest_8x6_210e_coco.py | 105 + configs/cornernet/metafile.yml | 83 + configs/dcn/README.md | 52 + ..._mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py | 5 + ...e_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py | 5 + ...rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py | 5 + ...scade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py | 5 + ...ascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py | 5 + ...aster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py | 5 + ...faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py | 5 + .../dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py | 12 + ...aster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py | 5 + ...cnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py | 5 + .../dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py | 12 + ...rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py | 16 + .../mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py | 5 + .../mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py | 5 + .../mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py | 5 + configs/dcn/metafile.yml | 335 ++ configs/deepfashion/README.md | 56 + .../mask_rcnn_r50_fpn_15e_deepfashion.py | 10 + configs/deformable_detr/README.md | 31 + .../deformable_detr_r50_16x2_50e_coco.py | 172 + ...eformable_detr_refine_r50_16x2_50e_coco.py | 2 + ..._detr_twostage_refine_r50_16x2_50e_coco.py | 2 + configs/deformable_detr/metafile.yml | 56 + configs/detectors/README.md | 59 + .../detectors/cascade_rcnn_r50_rfp_1x_coco.py | 28 + .../detectors/cascade_rcnn_r50_sac_1x_coco.py | 12 + .../detectors_cascade_rcnn_r50_1x_coco.py | 32 + .../detectors/detectors_htc_r101_20e_coco.py | 28 + .../detectors/detectors_htc_r50_1x_coco.py | 28 + configs/detectors/htc_r50_rfp_1x_coco.py | 24 + configs/detectors/htc_r50_sac_1x_coco.py | 8 + configs/detectors/metafile.yml | 114 + configs/detr/README.md | 27 + configs/detr/detr_r50_8x2_150e_coco.py | 150 + configs/detr/detr_r50_8x2_150e_coco_merge.py | 152 + configs/detr/metafile.yml | 33 + configs/double_heads/README.md | 22 + .../dh_faster_rcnn_r50_fpn_1x_coco.py | 23 + configs/double_heads/metafile.yml | 41 + configs/dynamic_rcnn/README.md | 20 + .../dynamic_rcnn_r50_fpn_1x_coco.py | 28 + configs/dynamic_rcnn/metafile.yml | 35 + configs/empirical_attention/README.md | 23 + ...ter_rcnn_r50_fpn_attention_0010_1x_coco.py | 13 + ...rcnn_r50_fpn_attention_0010_dcn_1x_coco.py | 16 + ...ter_rcnn_r50_fpn_attention_1111_1x_coco.py | 13 + ...rcnn_r50_fpn_attention_1111_dcn_1x_coco.py | 16 + configs/empirical_attention/metafile.yml | 103 + configs/fast_rcnn/README.md | 16 + .../fast_rcnn_r101_caffe_fpn_1x_coco.py | 7 + .../fast_rcnn/fast_rcnn_r101_fpn_1x_coco.py | 6 + .../fast_rcnn/fast_rcnn_r101_fpn_2x_coco.py | 6 + .../fast_rcnn_r50_caffe_fpn_1x_coco.py | 48 + .../fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py | 52 + .../fast_rcnn/fast_rcnn_r50_fpn_2x_coco.py | 5 + configs/faster_rcnn/README.md | 67 + .../faster_rcnn_r101_caffe_fpn_1x_coco.py | 7 + ...ter_rcnn_r101_caffe_fpn_mstrain_3x_coco.py | 49 + .../faster_rcnn_r101_fpn_1x_coco.py | 6 + .../faster_rcnn_r101_fpn_2x_coco.py | 6 + .../faster_rcnn_r101_fpn_mstrain_3x_coco.py | 7 + .../faster_rcnn_r50_caffe_c4_1x_coco.py | 39 + .../faster_rcnn_r50_caffe_dc5_1x_coco.py | 37 + ...ster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py | 42 + ...ster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py | 4 + .../faster_rcnn_r50_caffe_fpn_1x_coco.py | 41 + .../faster_rcnn_r50_caffe_fpn_90k_coco.py | 15 + ..._fpn_mstrain_1x_coco-person-bicycle-car.py | 9 + ...nn_r50_caffe_fpn_mstrain_1x_coco-person.py | 9 + ...ster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py | 46 + ...ster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py | 4 + ...ster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py | 47 + ...ter_rcnn_r50_caffe_fpn_mstrain_90k_coco.py | 15 + .../faster_rcnn_r50_fpn_1x_coco.py | 5 + .../faster_rcnn_r50_fpn_2x_coco.py | 5 + ...faster_rcnn_r50_fpn_bounded_iou_1x_coco.py | 6 + .../faster_rcnn_r50_fpn_ciou_1x_coco.py | 6 + .../faster_rcnn_r50_fpn_giou_1x_coco.py | 6 + .../faster_rcnn_r50_fpn_iou_1x_coco.py | 6 + .../faster_rcnn_r50_fpn_mstrain_3x_coco.py | 3 + .../faster_rcnn_r50_fpn_ohem_1x_coco.py | 2 + .../faster_rcnn_r50_fpn_soft_nms_1x_coco.py | 12 + .../faster_rcnn_x101_32x4d_fpn_1x_coco.py | 14 + .../faster_rcnn_x101_32x4d_fpn_2x_coco.py | 14 + ...ter_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py | 16 + ...ter_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py | 62 + .../faster_rcnn_x101_64x4d_fpn_1x_coco.py | 14 + .../faster_rcnn_x101_64x4d_fpn_2x_coco.py | 14 + ...ter_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py | 16 + configs/faster_rcnn/metafile.yml | 383 +++ configs/fcos/README.md | 35 + ...nreg-giou_r50_caffe_fpn_gn-head_1x_coco.py | 54 + ...-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py | 56 + ...os_center_r50_caffe_fpn_gn-head_1x_coco.py | 2 + .../fcos_r101_caffe_fpn_gn-head_1x_coco.py | 7 + ...ffe_fpn_gn-head_mstrain_640-800_2x_coco.py | 47 + .../fcos_r50_caffe_fpn_gn-head_1x_coco.py | 106 + .../fcos_r50_caffe_fpn_gn-head_4x4_1x_coco.py | 4 + ...ffe_fpn_gn-head_mstrain_640-800_2x_coco.py | 39 + ...x4d_fpn_gn-head_mstrain_640-800_2x_coco.py | 60 + configs/fcos/metafile.yml | 146 + configs/foveabox/README.md | 41 + ...ovea_align_r101_fpn_gn-head_4x4_2x_coco.py | 12 + ...fpn_gn-head_mstrain_640-800_4x4_2x_coco.py | 29 + ...fovea_align_r50_fpn_gn-head_4x4_2x_coco.py | 10 + ...fpn_gn-head_mstrain_640-800_4x4_2x_coco.py | 25 + .../foveabox/fovea_r101_fpn_4x4_1x_coco.py | 6 + .../foveabox/fovea_r101_fpn_4x4_2x_coco.py | 6 + configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py | 52 + configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py | 4 + configs/foveabox/metafile.yml | 172 + configs/fp16/README.md | 24 + .../fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py | 3 + .../fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py | 3 + ...k_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py | 7 + ..._rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py | 7 + configs/fp16/metafile.yml | 113 + .../fp16/retinanet_r50_fpn_fp16_1x_coco.py | 3 + configs/fpg/README.md | 30 + ...er_rcnn_r50_fpg-chn128_crop640_50e_coco.py | 9 + .../faster_rcnn_r50_fpg_crop640_50e_coco.py | 48 + .../faster_rcnn_r50_fpn_crop640_50e_coco.py | 68 + ...sk_rcnn_r50_fpg-chn128_crop640_50e_coco.py | 10 + .../fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py | 48 + .../fpg/mask_rcnn_r50_fpn_crop640_50e_coco.py | 74 + configs/fpg/metafile.yml | 104 + ...tinanet_r50_fpg-chn128_crop640_50e_coco.py | 5 + .../fpg/retinanet_r50_fpg_crop640_50e_coco.py | 53 + configs/free_anchor/README.md | 27 + configs/free_anchor/metafile.yml | 79 + .../retinanet_free_anchor_r101_fpn_1x_coco.py | 6 + .../retinanet_free_anchor_r50_fpn_1x_coco.py | 22 + ...anet_free_anchor_x101_32x4d_fpn_1x_coco.py | 13 + configs/fsaf/README.md | 45 + configs/fsaf/fsaf_r101_fpn_1x_coco.py | 6 + configs/fsaf/fsaf_r50_fpn_1x_coco.py | 48 + configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py | 14 + configs/fsaf/metafile.yml | 80 + configs/gcnet/README.md | 59 + ..._x101_32x4d_fpn_syncbn-backbone_1x_coco.py | 4 + ...fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py | 4 + ...kbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py | 11 + ...ckbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py | 11 + ...n_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py | 11 + ...pn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py | 11 + ...ask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py | 8 + ...mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py | 8 + ...k_rcnn_r101_fpn_syncbn-backbone_1x_coco.py | 4 + ...n_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py | 11 + ...pn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py | 11 + ...mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py | 8 + .../mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py | 8 + ...sk_rcnn_r50_fpn_syncbn-backbone_1x_coco.py | 4 + ...n_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py | 11 + ...pn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py | 11 + ..._x101_32x4d_fpn_syncbn-backbone_1x_coco.py | 4 + ...n_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py | 11 + ...pn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py | 11 + configs/gcnet/metafile.yml | 440 +++ configs/gfl/README.md | 32 + ...fl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py | 15 + configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py | 13 + configs/gfl/gfl_r50_fpn_1x_coco.py | 57 + configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py | 22 + ...1_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py | 18 + .../gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py | 16 + configs/gfl/metafile.yml | 134 + configs/ghm/README.md | 23 + configs/ghm/metafile.yml | 101 + configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py | 6 + configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py | 19 + .../retinanet_ghm_x101_32x4d_fpn_1x_coco.py | 14 + .../retinanet_ghm_x101_64x4d_fpn_1x_coco.py | 14 + configs/gn+ws/README.md | 44 + .../faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py | 6 + .../faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py | 16 + ...r_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py | 18 + ...er_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py | 18 + ..._rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py | 4 + .../mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py | 6 + ...k_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py | 4 + .../mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py | 20 + ...x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py | 4 + ...k_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py | 19 + ..._x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py | 4 + ...sk_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py | 19 + configs/gn+ws/metafile.yml | 263 ++ configs/gn/README.md | 31 + .../gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py | 7 + .../gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py | 5 + .../gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py | 49 + .../gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py | 5 + ...ask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py | 17 + ...ask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py | 5 + configs/gn/metafile.yml | 162 + configs/grid_rcnn/README.md | 35 + .../grid_rcnn_r101_fpn_gn-head_2x_coco.py | 7 + .../grid_rcnn_r50_fpn_gn-head_1x_coco.py | 11 + .../grid_rcnn_r50_fpn_gn-head_2x_coco.py | 131 + ...rid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py | 24 + ...rid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py | 13 + configs/grid_rcnn/metafile.yml | 101 + configs/groie/README.md | 62 + .../faster_rcnn_r50_fpn_groie_1x_coco.py | 25 + ...grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py | 45 + ...cbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py | 45 + .../groie/mask_rcnn_r50_fpn_groie_1x_coco.py | 45 + ...cbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py | 45 + configs/groie/metafile.yml | 93 + configs/guided_anchoring/README.md | 49 + .../ga_fast_r50_caffe_fpn_1x_coco.py | 65 + .../ga_faster_r101_caffe_fpn_1x_coco.py | 7 + .../ga_faster_r50_caffe_fpn_1x_coco.py | 65 + .../ga_faster_r50_fpn_1x_coco.py | 65 + .../ga_faster_x101_32x4d_fpn_1x_coco.py | 14 + .../ga_faster_x101_64x4d_fpn_1x_coco.py | 14 + .../ga_retinanet_r101_caffe_fpn_1x_coco.py | 7 + .../ga_retinanet_r101_caffe_fpn_mstrain_2x.py | 169 + .../ga_retinanet_r50_caffe_fpn_1x_coco.py | 62 + .../ga_retinanet_r50_fpn_1x_coco.py | 62 + .../ga_retinanet_x101_32x4d_fpn_1x_coco.py | 14 + .../ga_retinanet_x101_64x4d_fpn_1x_coco.py | 14 + .../ga_rpn_r101_caffe_fpn_1x_coco.py | 8 + .../ga_rpn_r50_caffe_fpn_1x_coco.py | 58 + .../ga_rpn_r50_fpn_1x_coco.py | 58 + .../ga_rpn_x101_32x4d_fpn_1x_coco.py | 14 + .../ga_rpn_x101_64x4d_fpn_1x_coco.py | 14 + configs/guided_anchoring/metafile.yml | 246 ++ configs/hrnet/README.md | 88 + ...cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py | 11 + ...cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py | 40 + ...cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py | 12 + .../cascade_rcnn_hrnetv2p_w18_20e_coco.py | 11 + .../cascade_rcnn_hrnetv2p_w32_20e_coco.py | 40 + .../cascade_rcnn_hrnetv2p_w40_20e_coco.py | 12 + .../hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py | 11 + .../hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py | 5 + .../hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py | 37 + .../hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py | 4 + .../hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py | 11 + .../hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py | 4 + .../fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py | 10 + .../fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py | 4 + ...w18_gn-head_mstrain_640-800_4x4_2x_coco.py | 10 + .../fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py | 70 + .../fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py | 4 + ...w32_gn-head_mstrain_640-800_4x4_2x_coco.py | 39 + ...w40_gn-head_mstrain_640-800_4x4_2x_coco.py | 11 + configs/hrnet/htc_hrnetv2p_w18_20e_coco.py | 10 + configs/hrnet/htc_hrnetv2p_w32_20e_coco.py | 37 + configs/hrnet/htc_hrnetv2p_w40_20e_coco.py | 11 + configs/hrnet/htc_hrnetv2p_w40_28e_coco.py | 4 + .../hrnet/htc_x101_64x4d_fpn_16x1_28e_coco.py | 4 + .../hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py | 10 + .../hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py | 4 + .../hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py | 37 + .../hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py | 4 + .../hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py | 11 + .../hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py | 4 + configs/hrnet/metafile.yml | 604 ++++ configs/htc/README.md | 57 + configs/htc/htc_r101_fpn_20e_coco.py | 9 + configs/htc/htc_r50_fpn_1x_coco.py | 56 + configs/htc/htc_r50_fpn_20e_coco.py | 4 + .../htc_without_semantic_r50_fpn_1x_coco.py | 236 ++ .../htc/htc_x101_32x4d_fpn_16x1_20e_coco.py | 19 + .../htc/htc_x101_64x4d_fpn_16x1_20e_coco.py | 19 + ...nv_c3-c5_mstrain_400_1400_16x1_20e_coco.py | 43 + configs/htc/metafile.yml | 165 + configs/instaboost/README.md | 44 + ...e_mask_rcnn_r101_fpn_instaboost_4x_coco.py | 7 + ...de_mask_rcnn_r50_fpn_instaboost_4x_coco.py | 28 + ..._rcnn_x101_64x4d_fpn_instaboost_4x_coco.py | 14 + .../mask_rcnn_r101_fpn_instaboost_4x_coco.py | 6 + .../mask_rcnn_r50_fpn_instaboost_4x_coco.py | 28 + ..._rcnn_x101_64x4d_fpn_instaboost_4x_coco.py | 14 + configs/instaboost/metafile.yml | 99 + configs/ld/README.md | 31 + .../ld/ld_r101_gflv1_r101dcn_fpn_coco_2x.py | 44 + configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py | 62 + configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py | 19 + configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py | 19 + configs/ld/metafile.yml | 72 + configs/legacy_1.x/README.md | 53 + .../cascade_mask_rcnn_r50_fpn_1x_coco_v1.py | 79 + .../faster_rcnn_r50_fpn_1x_coco_v1.py | 38 + .../mask_rcnn_r50_fpn_1x_coco_v1.py | 34 + .../retinanet_r50_caffe_fpn_1x_coco_v1.py | 41 + .../retinanet_r50_fpn_1x_coco_v1.py | 17 + configs/legacy_1.x/ssd300_coco_v1.py | 79 + configs/libra_rcnn/README.md | 41 + .../libra_fast_rcnn_r50_fpn_1x_coco.py | 50 + .../libra_faster_rcnn_r101_fpn_1x_coco.py | 6 + .../libra_faster_rcnn_r50_fpn_1x_coco.py | 41 + ...ibra_faster_rcnn_x101_64x4d_fpn_1x_coco.py | 14 + .../libra_retinanet_r50_fpn_1x_coco.py | 26 + configs/libra_rcnn/metafile.yml | 99 + configs/lvis/README.md | 44 + ..._r101_fpn_sample1e-3_mstrain_1x_lvis_v1.py | 6 + ...101_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py | 6 + ...n_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py | 31 + ...r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py | 31 + ...32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py | 14 + ...x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py | 14 + ...64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py | 14 + ...x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py | 14 + configs/mask_rcnn/README.md | 48 + .../mask_rcnn_r101_caffe_fpn_1x_coco.py | 7 + ...cnn_r101_caffe_fpn_mstrain-poly_3x_coco.py | 55 + .../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py | 6 + .../mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py | 6 + ...mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py | 10 + .../mask_rcnn_r50_caffe_c4_1x_coco.py | 39 + .../mask_rcnn_r50_caffe_fpn_1x_coco.py | 40 + ...rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py | 49 + ...rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py | 4 + ...rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py | 4 + ...mask_rcnn_r50_caffe_fpn_mstrain_1x_coco.py | 45 + ...mask_rcnn_r50_caffe_fpn_poly_1x_coco_v1.py | 61 + .../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py | 5 + .../mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py | 5 + .../mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py | 4 + .../mask_rcnn_r50_fpn_poly_1x_coco.py | 23 + .../mask_rcnn_x101_32x4d_fpn_1x_coco.py | 14 + .../mask_rcnn_x101_32x4d_fpn_2x_coco.py | 14 + ...cnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py | 18 + .../mask_rcnn_x101_32x8d_fpn_1x_coco.py | 65 + ...cnn_x101_32x8d_fpn_mstrain-poly_1x_coco.py | 60 + ...cnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py | 85 + .../mask_rcnn_x101_64x4d_fpn_1x_coco.py | 14 + .../mask_rcnn_x101_64x4d_fpn_2x_coco.py | 14 + ...cnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py | 18 + configs/mask_rcnn/metafile.yml | 419 +++ configs/ms_rcnn/README.md | 26 + configs/ms_rcnn/metafile.yml | 159 + .../ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py | 7 + .../ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py | 4 + .../ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py | 16 + .../ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py | 4 + configs/ms_rcnn/ms_rcnn_r50_fpn_1x_coco.py | 16 + .../ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py | 14 + .../ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py | 14 + .../ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py | 4 + configs/nas_fcos/README.md | 25 + configs/nas_fcos/metafile.yml | 44 + ...shead_r50_caffe_fpn_gn-head_4x4_1x_coco.py | 100 + ...shead_r50_caffe_fpn_gn-head_4x4_1x_coco.py | 99 + configs/nas_fpn/README.md | 26 + configs/nas_fpn/metafile.yml | 59 + .../retinanet_r50_fpn_crop640_50e_coco.py | 80 + .../retinanet_r50_nasfpn_crop640_50e_coco.py | 79 + configs/paa/README.md | 35 + configs/paa/metafile.yml | 104 + configs/paa/paa_r101_fpn_1x_coco.py | 6 + configs/paa/paa_r101_fpn_2x_coco.py | 3 + configs/paa/paa_r101_fpn_mstrain_3x_coco.py | 6 + configs/paa/paa_r50_fpn_1.5x_coco.py | 3 + configs/paa/paa_r50_fpn_1x_coco.py | 70 + configs/paa/paa_r50_fpn_2x_coco.py | 3 + configs/paa/paa_r50_fpn_mstrain_3x_coco.py | 20 + configs/pafpn/README.md | 26 + .../pafpn/faster_rcnn_r50_pafpn_1x_coco.py | 8 + configs/pafpn/metafile.yml | 38 + configs/panoptic_fpn/README.md | 50 + configs/panoptic_fpn/metafile.yml | 70 + .../panoptic_fpn_r101_fpn_1x_coco.py | 6 + .../panoptic_fpn_r101_fpn_mstrain_3x_coco.py | 6 + .../panoptic_fpn_r50_fpn_1x_coco.py | 33 + .../panoptic_fpn_r50_fpn_mstrain_3x_coco.py | 61 + configs/pascal_voc/README.md | 23 + .../faster_rcnn_r50_fpn_1x_voc0712.py | 14 + .../faster_rcnn_r50_fpn_1x_voc0712_cocofmt.py | 75 + .../retinanet_r50_fpn_1x_voc0712.py | 14 + configs/pascal_voc/ssd300_voc0712.py | 69 + configs/pascal_voc/ssd512_voc0712.py | 52 + configs/pisa/README.md | 40 + configs/pisa/metafile.yml | 110 + .../pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py | 30 + ...pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py | 30 + .../pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py | 30 + .../pisa_mask_rcnn_x101_32x4d_fpn_1x_coco.py | 30 + .../pisa/pisa_retinanet_r50_fpn_1x_coco.py | 7 + .../pisa_retinanet_x101_32x4d_fpn_1x_coco.py | 7 + configs/pisa/pisa_ssd300_coco.py | 8 + configs/pisa/pisa_ssd512_coco.py | 8 + configs/pix2seq/README.md | 21 + configs/pix2seq/metafile.yml | 33 + configs/pix2seq/pix2seq_r50_8x4_300e_coco.py | 156 + configs/point_rend/README.md | 23 + configs/point_rend/metafile.yml | 54 + ...oint_rend_r50_caffe_fpn_mstrain_1x_coco.py | 44 + ...oint_rend_r50_caffe_fpn_mstrain_3x_coco.py | 4 + configs/pvt/README.md | 43 + configs/pvt/metafile.yml | 136 + configs/pvt/retinanet_pvt-l_fpn_1x_coco.py | 7 + configs/pvt/retinanet_pvt-m_fpn_1x_coco.py | 6 + configs/pvt/retinanet_pvt-s_fpn_1x_coco.py | 6 + configs/pvt/retinanet_pvt-t_fpn_1x_coco.py | 16 + configs/pvt/retinanet_pvtv2-b0_fpn_1x_coco.py | 17 + configs/pvt/retinanet_pvtv2-b1_fpn_1x_coco.py | 7 + configs/pvt/retinanet_pvtv2-b2_fpn_1x_coco.py | 8 + configs/pvt/retinanet_pvtv2-b3_fpn_1x_coco.py | 8 + configs/pvt/retinanet_pvtv2-b4_fpn_1x_coco.py | 13 + configs/pvt/retinanet_pvtv2-b5_fpn_1x_coco.py | 14 + configs/queryinst/README.md | 26 + configs/queryinst/metafile.yml | 100 + ..._proposals_crop_mstrain_480-800_3x_coco.py | 7 + ...ryinst_r101_fpn_mstrain_480-800_3x_coco.py | 7 + .../queryinst/queryinst_r50_fpn_1x_coco.py | 138 + ..._proposals_crop_mstrain_480-800_3x_coco.py | 54 + ...eryinst_r50_fpn_mstrain_480-800_3x_coco.py | 23 + configs/regnet/README.md | 110 + ..._rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py | 17 + ..._rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py | 63 + ..._rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py | 17 + ...sk_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py | 17 + ..._rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py | 17 + ..._rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py | 17 + .../faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py | 57 + .../faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py | 3 + ..._rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py | 61 + ..._rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py | 17 + ...er_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py | 17 + ..._rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py | 17 + ..._regnetx-1.6GF_fpn_mstrain-poly_3x_coco.py | 26 + .../mask_rcnn_regnetx-12GF_fpn_1x_coco.py | 17 + .../mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py | 58 + ..._regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py | 7 + ..._rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py | 66 + ..._regnetx-400MF_fpn_mstrain-poly_3x_coco.py | 26 + .../mask_rcnn_regnetx-4GF_fpn_1x_coco.py | 17 + ...nn_regnetx-4GF_fpn_mstrain-poly_3x_coco.py | 26 + .../mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py | 17 + ..._regnetx-800MF_fpn_mstrain-poly_3x_coco.py | 26 + .../mask_rcnn_regnetx-8GF_fpn_1x_coco.py | 17 + configs/regnet/metafile.yml | 437 +++ .../retinanet_regnetx-1.6GF_fpn_1x_coco.py | 17 + .../retinanet_regnetx-3.2GF_fpn_1x_coco.py | 59 + .../retinanet_regnetx-800MF_fpn_1x_coco.py | 17 + configs/reppoints/README.md | 54 + ...50_grid_center_fpn_gn-neck+head_1x_coco.py | 2 + .../bbox_r50_grid_fpn_gn-neck+head_1x_coco.py | 13 + configs/reppoints/metafile.yml | 181 + configs/reppoints/reppoints.png | Bin 0 -> 1198109 bytes ...nts_minmax_r50_fpn_gn-neck+head_1x_coco.py | 2 + ...01_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py | 8 + ...ts_moment_r101_fpn_gn-neck+head_2x_coco.py | 6 + .../reppoints_moment_r50_fpn_1x_coco.py | 67 + ...nts_moment_r50_fpn_gn-neck+head_1x_coco.py | 4 + ...nts_moment_r50_fpn_gn-neck+head_2x_coco.py | 3 + ...01_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py | 16 + ...ial_minmax_r50_fpn_gn-neck+head_1x_coco.py | 2 + configs/res2net/README.md | 65 + .../cascade_mask_rcnn_r2_101_fpn_20e_coco.py | 10 + .../cascade_rcnn_r2_101_fpn_20e_coco.py | 10 + .../res2net/faster_rcnn_r2_101_fpn_2x_coco.py | 10 + configs/res2net/htc_r2_101_fpn_20e_coco.py | 13 + .../res2net/mask_rcnn_r2_101_fpn_2x_coco.py | 10 + configs/res2net/metafile.yml | 94 + configs/resnest/README.md | 44 + ...pn_syncbn-backbone+head_mstrain_1x_coco.py | 7 + ...pn_syncbn-backbone+head_mstrain_1x_coco.py | 118 + ...cbn-backbone+head_mstrain-range_1x_coco.py | 7 + ...cbn-backbone+head_mstrain-range_1x_coco.py | 116 + ...cbn-backbone+head_mstrain-range_1x_coco.py | 7 + ...cbn-backbone+head_mstrain-range_1x_coco.py | 62 + ...pn_syncbn-backbone+head_mstrain_1x_coco.py | 7 + ...pn_syncbn-backbone+head_mstrain_1x_coco.py | 64 + configs/resnest/metafile.yml | 136 + configs/retinanet/README.md | 40 + configs/retinanet/metafile.yml | 261 ++ .../retinanet_r101_caffe_fpn_1x_coco.py | 7 + ...etinanet_r101_caffe_fpn_mstrain_3x_coco.py | 7 + .../retinanet/retinanet_r101_fpn_1x_coco.py | 6 + .../retinanet/retinanet_r101_fpn_2x_coco.py | 6 + ...inanet_r101_fpn_mstrain_640-800_3x_coco.py | 6 + .../retinanet_r50_caffe_fpn_1x_coco.py | 41 + ...retinanet_r50_caffe_fpn_mstrain_1x_coco.py | 46 + ...retinanet_r50_caffe_fpn_mstrain_2x_coco.py | 4 + ...retinanet_r50_caffe_fpn_mstrain_3x_coco.py | 4 + .../retinanet/retinanet_r50_fpn_1x_coco.py | 7 + .../retinanet/retinanet_r50_fpn_2x_coco.py | 4 + .../retinanet/retinanet_r50_fpn_90k_coco.py | 15 + ...tinanet_r50_fpn_mstrain_640-800_3x_coco.py | 5 + .../retinanet_x101_32x4d_fpn_1x_coco.py | 14 + .../retinanet_x101_32x4d_fpn_2x_coco.py | 14 + .../retinanet_x101_64x4d_fpn_1x_coco.py | 14 + .../retinanet_x101_64x4d_fpn_2x_coco.py | 14 + ..._x101_64x4d_fpn_mstrain_640-800_3x_coco.py | 8 + configs/rpn/README.md | 29 + configs/rpn/rpn_r101_caffe_fpn_1x_coco.py | 7 + configs/rpn/rpn_r101_fpn_1x_coco.py | 6 + configs/rpn/rpn_r101_fpn_2x_coco.py | 6 + configs/rpn/rpn_r50_caffe_c4_1x_coco.py | 38 + configs/rpn/rpn_r50_caffe_fpn_1x_coco.py | 41 + configs/rpn/rpn_r50_fpn_1x_coco.py | 18 + configs/rpn/rpn_r50_fpn_2x_coco.py | 5 + configs/rpn/rpn_x101_32x4d_fpn_1x_coco.py | 14 + configs/rpn/rpn_x101_32x4d_fpn_2x_coco.py | 14 + configs/rpn/rpn_x101_64x4d_fpn_1x_coco.py | 14 + configs/rpn/rpn_x101_64x4d_fpn_2x_coco.py | 14 + configs/sabl/README.md | 37 + configs/sabl/metafile.yml | 140 + .../sabl_cascade_rcnn_r101_fpn_1x_coco.py | 90 + .../sabl/sabl_cascade_rcnn_r50_fpn_1x_coco.py | 86 + .../sabl/sabl_faster_rcnn_r101_fpn_1x_coco.py | 38 + .../sabl/sabl_faster_rcnn_r50_fpn_1x_coco.py | 34 + .../sabl/sabl_retinanet_r101_fpn_1x_coco.py | 54 + .../sabl_retinanet_r101_fpn_gn_1x_coco.py | 56 + ...etinanet_r101_fpn_gn_2x_ms_480_960_coco.py | 73 + ...etinanet_r101_fpn_gn_2x_ms_640_800_coco.py | 73 + .../sabl/sabl_retinanet_r50_fpn_1x_coco.py | 50 + .../sabl/sabl_retinanet_r50_fpn_gn_1x_coco.py | 52 + configs/scnet/README.md | 51 + configs/scnet/metafile.yml | 116 + configs/scnet/scnet_r101_fpn_20e_coco.py | 6 + configs/scnet/scnet_r50_fpn_1x_coco.py | 136 + configs/scnet/scnet_r50_fpn_20e_coco.py | 4 + .../scnet/scnet_x101_64x4d_fpn_20e_coco.py | 15 + .../scnet_x101_64x4d_fpn_8x1_20e_coco.py | 3 + configs/scratch/README.md | 25 + ...ter_rcnn_r50_fpn_gn-all_scratch_6x_coco.py | 24 + ...ask_rcnn_r50_fpn_gn-all_scratch_6x_coco.py | 25 + configs/scratch/metafile.yml | 48 + configs/seesaw_loss/README.md | 39 + ...n_random_seesaw_loss_mstrain_2x_lvis_v1.py | 132 + ...saw_loss_normed_mask_mstrain_2x_lvis_v1.py | 5 + ...mple1e-3_seesaw_loss_mstrain_2x_lvis_v1.py | 98 + ...saw_loss_normed_mask_mstrain_2x_lvis_v1.py | 5 + ...n_random_seesaw_loss_mstrain_2x_lvis_v1.py | 6 + ...saw_loss_normed_mask_mstrain_2x_lvis_v1.py | 6 + ...mple1e-3_seesaw_loss_mstrain_2x_lvis_v1.py | 6 + ...saw_loss_normed_mask_mstrain_2x_lvis_v1.py | 6 + ...n_random_seesaw_loss_mstrain_2x_lvis_v1.py | 75 + ...saw_loss_normed_mask_mstrain_2x_lvis_v1.py | 5 + ...mple1e-3_seesaw_loss_mstrain_2x_lvis_v1.py | 41 + ...saw_loss_normed_mask_mstrain_2x_lvis_v1.py | 5 + configs/selfsup_pretrain/README.md | 95 + ...sk_rcnn_r50_fpn_mocov2-pretrain_1x_coco.py | 13 + ...rcnn_r50_fpn_mocov2-pretrain_ms-2x_coco.py | 32 + ...mask_rcnn_r50_fpn_swav-pretrain_1x_coco.py | 13 + ...k_rcnn_r50_fpn_swav-pretrain_ms-2x_coco.py | 32 + configs/solo/README.md | 42 + .../decoupled_solo_light_r50_fpn_3x_coco.py | 63 + .../solo/decoupled_solo_r50_fpn_1x_coco.py | 28 + .../solo/decoupled_solo_r50_fpn_3x_coco.py | 25 + configs/solo/metafile.yml | 115 + configs/solo/solo_r50_fpn_1x_coco.py | 53 + configs/solo/solo_r50_fpn_3x_coco.py | 28 + configs/sparse_rcnn/README.md | 28 + configs/sparse_rcnn/metafile.yml | 80 + ..._proposals_crop_mstrain_480-800_3x_coco.py | 7 + ...e_rcnn_r101_fpn_mstrain_480-800_3x_coco.py | 7 + .../sparse_rcnn_r50_fpn_1x_coco.py | 95 + ..._proposals_crop_mstrain_480-800_3x_coco.py | 52 + ...se_rcnn_r50_fpn_mstrain_480-800_3x_coco.py | 23 + configs/ssd/README.md | 52 + configs/ssd/metafile.yml | 78 + configs/ssd/ssd300_coco.py | 66 + configs/ssd/ssd512_coco.py | 79 + .../ssdlite_mobilenetv2_scratch_600e_coco.py | 145 + configs/strong_baselines/README.md | 18 + ..._fpn_syncbn-all_rpn-2conv_lsj_100e_coco.py | 80 + ...syncbn-all_rpn-2conv_lsj_100e_fp16_coco.py | 2 + ..._fpn_syncbn-all_rpn-2conv_lsj_400e_coco.py | 6 + ..._fpn_syncbn-all_rpn-2conv_lsj_100e_coco.py | 22 + ...syncbn-all_rpn-2conv_lsj_100e_fp16_coco.py | 3 + ...0_fpn_syncbn-all_rpn-2conv_lsj_50e_coco.py | 5 + configs/swin/README.md | 25 + ...n_swin-s-p4-w7_fpn_fp16_ms-crop-3x_coco.py | 6 + .../mask_rcnn_swin-t-p4-w7_fpn_1x_coco.py | 42 + ...n_swin-t-p4-w7_fpn_fp16_ms-crop-3x_coco.py | 3 + ...k_rcnn_swin-t-p4-w7_fpn_ms-crop-3x_coco.py | 91 + configs/swin/metafile.yml | 85 + configs/tridentnet/README.md | 28 + configs/tridentnet/metafile.yml | 55 + .../tridentnet_r50_caffe_1x_coco.py | 55 + .../tridentnet_r50_caffe_mstrain_1x_coco.py | 22 + .../tridentnet_r50_caffe_mstrain_3x_coco.py | 4 + configs/vfnet/README.md | 43 + configs/vfnet/metafile.yml | 116 + configs/vfnet/vfnet_r101_fpn_1x_coco.py | 6 + configs/vfnet/vfnet_r101_fpn_2x_coco.py | 8 + ...t_r101_fpn_mdconv_c3-c5_mstrain_2x_coco.py | 15 + .../vfnet/vfnet_r101_fpn_mstrain_2x_coco.py | 6 + ...r2_101_fpn_mdconv_c3-c5_mstrain_2x_coco.py | 18 + .../vfnet/vfnet_r2_101_fpn_mstrain_2x_coco.py | 16 + configs/vfnet/vfnet_r50_fpn_1x_coco.py | 107 + ...et_r50_fpn_mdconv_c3-c5_mstrain_2x_coco.py | 6 + .../vfnet/vfnet_r50_fpn_mstrain_2x_coco.py | 39 + ..._32x4d_fpn_mdconv_c3-c5_mstrain_2x_coco.py | 17 + .../vfnet_x101_32x4d_fpn_mstrain_2x_coco.py | 15 + ..._64x4d_fpn_mdconv_c3-c5_mstrain_2x_coco.py | 17 + .../vfnet_x101_64x4d_fpn_mstrain_2x_coco.py | 15 + configs/wider_face/README.md | 43 + configs/wider_face/ssd300_wider_face.py | 18 + configs/yolact/README.md | 71 + configs/yolact/metafile.yml | 78 + configs/yolact/yolact_r101_1x8_coco.py | 7 + configs/yolact/yolact_r50_1x8_coco.py | 160 + configs/yolact/yolact_r50_8x8_coco.py | 11 + configs/yolo/README.md | 45 + configs/yolo/metafile.yml | 124 + configs/yolo/yolov3_d53_320_273e_coco.py | 42 + .../yolov3_d53_fp16_mstrain-608_273e_coco.py | 3 + .../yolo/yolov3_d53_mstrain-416_273e_coco.py | 42 + .../yolo/yolov3_d53_mstrain-608_273e_coco.py | 127 + .../yolo/yolov3_mobilenetv2_320_300e_coco.py | 53 + ...olov3_mobilenetv2_mstrain-416_300e_coco.py | 137 + configs/yolof/README.md | 25 + configs/yolof/metafile.yml | 32 + configs/yolof/yolof_r50_c5_8x8_1x_coco.py | 105 + .../yolof/yolof_r50_c5_8x8_iter-1x_coco.py | 14 + configs/yolox/README.md | 25 + configs/yolox/metafile.yml | 33 + configs/yolox/yolox_l_8x8_300e_coco.py | 8 + configs/yolox/yolox_m_8x8_300e_coco.py | 8 + configs/yolox/yolox_nano_8x8_300e_coco.py | 11 + configs/yolox/yolox_s_8x8_300e_coco.py | 142 + configs/yolox/yolox_tiny_8x8_300e_coco.py | 78 + configs/yolox/yolox_x_8x8_300e_coco.py | 8 + demo/MMDet_Tutorial.ipynb | 1656 +++++++++ demo/create_result_gif.py | 163 + demo/demo.jpg | Bin 0 -> 259865 bytes demo/demo.mp4 | Bin 0 -> 297688 bytes demo/image_demo.py | 50 + demo/inference_demo.ipynb | 100 + demo/video_demo.py | 61 + demo/webcam_demo.py | 47 + docker/Dockerfile | 24 + docker/serve/Dockerfile | 49 + docker/serve/config.properties | 5 + docker/serve/entrypoint.sh | 12 + docs/1_exist_data_model.md | 602 ++++ docs/2_new_data_model.md | 263 ++ docs/3_exist_data_new_model.md | 275 ++ docs/Makefile | 20 + docs/_static/css/readthedocs.css | 6 + docs/_static/image/mmdet-logo.png | Bin 0 -> 32181 bytes docs/api.rst | 108 + docs/changelog.md | 1201 +++++++ docs/compatibility.md | 143 + docs/conf.py | 178 + docs/conventions.md | 78 + docs/faq.md | 90 + docs/get_started.md | 246 ++ docs/index.rst | 57 + docs/make.bat | 35 + docs/model_zoo.md | 341 ++ docs/projects.md | 58 + docs/robustness_benchmarking.md | 110 + docs/stat.py | 64 + docs/switch_language.md | 3 + docs/tutorials/config.md | 544 +++ docs/tutorials/customize_dataset.md | 542 +++ docs/tutorials/customize_losses.md | 126 + docs/tutorials/customize_models.md | 363 ++ docs/tutorials/customize_runtime.md | 323 ++ docs/tutorials/data_pipeline.md | 199 ++ docs/tutorials/finetune.md | 89 + docs/tutorials/index.rst | 14 + docs/tutorials/init_cfg.md | 160 + docs/tutorials/onnx2tensorrt.md | 104 + docs/tutorials/pytorch2onnx.md | 332 ++ docs/useful_tools.md | 492 +++ docs_zh-CN/1_exist_data_model.md | 569 ++++ docs_zh-CN/2_new_data_model.md | 264 ++ docs_zh-CN/3_exist_data_new_model.md | 274 ++ docs_zh-CN/Makefile | 20 + docs_zh-CN/_static/css/readthedocs.css | 6 + docs_zh-CN/_static/image/mmdet-logo.png | Bin 0 -> 32181 bytes docs_zh-CN/api.rst | 108 + docs_zh-CN/compatibility.md | 144 + docs_zh-CN/conf.py | 180 + docs_zh-CN/conventions.md | 74 + docs_zh-CN/faq.md | 91 + docs_zh-CN/get_started.md | 247 ++ docs_zh-CN/index.rst | 54 + docs_zh-CN/make.bat | 35 + docs_zh-CN/model_zoo.md | 335 ++ docs_zh-CN/projects.md | 48 + docs_zh-CN/robustness_benchmarking.md | 109 + docs_zh-CN/stat.py | 64 + docs_zh-CN/switch_language.md | 3 + docs_zh-CN/tutorials/config.md | 522 +++ docs_zh-CN/tutorials/customize_dataset.md | 457 +++ docs_zh-CN/tutorials/customize_losses.md | 125 + docs_zh-CN/tutorials/customize_models.md | 1 + docs_zh-CN/tutorials/customize_runtime.md | 1 + docs_zh-CN/tutorials/data_pipeline.md | 190 ++ docs_zh-CN/tutorials/finetune.md | 1 + docs_zh-CN/tutorials/index.rst | 12 + docs_zh-CN/tutorials/onnx2tensorrt.md | 1 + docs_zh-CN/tutorials/pytorch2onnx.md | 1 + docs_zh-CN/useful_tools.md | 1 + mmdet/__init__.py | 29 + mmdet/apis/__init__.py | 12 + mmdet/apis/inference.py | 241 ++ mmdet/apis/test.py | 190 ++ mmdet/apis/train.py | 213 ++ mmdet/core/__init__.py | 9 + mmdet/core/anchor/__init__.py | 14 + mmdet/core/anchor/anchor_generator.py | 866 +++++ mmdet/core/anchor/builder.py | 19 + mmdet/core/anchor/point_generator.py | 263 ++ mmdet/core/anchor/utils.py | 72 + mmdet/core/bbox/__init__.py | 28 + mmdet/core/bbox/assigners/__init__.py | 19 + .../bbox/assigners/approx_max_iou_assigner.py | 146 + mmdet/core/bbox/assigners/assign_result.py | 205 ++ mmdet/core/bbox/assigners/atss_assigner.py | 179 + mmdet/core/bbox/assigners/base_assigner.py | 10 + .../bbox/assigners/center_region_assigner.py | 336 ++ mmdet/core/bbox/assigners/grid_assigner.py | 156 + .../core/bbox/assigners/hungarian_assigner.py | 146 + mmdet/core/bbox/assigners/max_iou_assigner.py | 213 ++ mmdet/core/bbox/assigners/point_assigner.py | 134 + mmdet/core/bbox/assigners/region_assigner.py | 222 ++ mmdet/core/bbox/assigners/sim_ota_assigner.py | 254 ++ mmdet/core/bbox/assigners/uniform_assigner.py | 135 + mmdet/core/bbox/builder.py | 21 + mmdet/core/bbox/coder/__init__.py | 15 + mmdet/core/bbox/coder/base_bbox_coder.py | 18 + mmdet/core/bbox/coder/bucketing_bbox_coder.py | 351 ++ .../core/bbox/coder/delta_xywh_bbox_coder.py | 392 +++ .../bbox/coder/distance_point_bbox_coder.py | 62 + .../coder/legacy_delta_xywh_bbox_coder.py | 216 ++ mmdet/core/bbox/coder/pseudo_bbox_coder.py | 19 + mmdet/core/bbox/coder/tblr_bbox_coder.py | 206 ++ mmdet/core/bbox/coder/yolo_bbox_coder.py | 83 + mmdet/core/bbox/demodata.py | 42 + mmdet/core/bbox/iou_calculators/__init__.py | 5 + mmdet/core/bbox/iou_calculators/builder.py | 9 + .../bbox/iou_calculators/iou2d_calculator.py | 261 ++ mmdet/core/bbox/match_costs/__init__.py | 8 + mmdet/core/bbox/match_costs/builder.py | 9 + mmdet/core/bbox/match_costs/match_cost.py | 185 ++ mmdet/core/bbox/samplers/__init__.py | 16 + mmdet/core/bbox/samplers/base_sampler.py | 102 + mmdet/core/bbox/samplers/combined_sampler.py | 21 + .../samplers/instance_balanced_pos_sampler.py | 56 + .../bbox/samplers/iou_balanced_neg_sampler.py | 158 + mmdet/core/bbox/samplers/ohem_sampler.py | 108 + mmdet/core/bbox/samplers/pseudo_sampler.py | 42 + mmdet/core/bbox/samplers/random_sampler.py | 82 + mmdet/core/bbox/samplers/sampling_result.py | 153 + mmdet/core/bbox/samplers/score_hlr_sampler.py | 265 ++ mmdet/core/bbox/transforms.py | 254 ++ mmdet/core/data_structures/__init__.py | 5 + mmdet/core/data_structures/general_data.py | 316 ++ mmdet/core/data_structures/instance_data.py | 188 ++ mmdet/core/evaluation/__init__.py | 16 + mmdet/core/evaluation/bbox_overlaps.py | 65 + mmdet/core/evaluation/class_names.py | 117 + mmdet/core/evaluation/eval_hooks.py | 61 + mmdet/core/evaluation/mean_ap.py | 509 +++ mmdet/core/evaluation/recall.py | 197 ++ mmdet/core/export/__init__.py | 12 + mmdet/core/export/model_wrappers.py | 183 + mmdet/core/export/onnx_helper.py | 223 ++ mmdet/core/export/pytorch2onnx.py | 159 + mmdet/core/hook/__init__.py | 14 + mmdet/core/hook/checkloss_hook.py | 24 + mmdet/core/hook/ema.py | 130 + mmdet/core/hook/pix2seq_lrupdater_hook.py | 30 + mmdet/core/hook/sync_norm_hook.py | 50 + mmdet/core/hook/sync_random_size_hook.py | 72 + mmdet/core/hook/yolox_lrupdater_hook.py | 67 + mmdet/core/hook/yolox_mode_switch_hook.py | 38 + mmdet/core/mask/__init__.py | 9 + mmdet/core/mask/mask_target.py | 127 + mmdet/core/mask/structures.py | 1071 ++++++ mmdet/core/mask/utils.py | 64 + mmdet/core/post_processing/__init__.py | 10 + mmdet/core/post_processing/bbox_nms.py | 171 + mmdet/core/post_processing/matrix_nms.py | 121 + mmdet/core/post_processing/merge_augs.py | 154 + mmdet/core/utils/__init__.py | 13 + mmdet/core/utils/dist_utils.py | 151 + mmdet/core/utils/misc.py | 208 ++ mmdet/core/visualization/__init__.py | 5 + mmdet/core/visualization/image.py | 309 ++ mmdet/datasets/__init__.py | 28 + mmdet/datasets/api_wrappers/__init__.py | 4 + mmdet/datasets/api_wrappers/coco_api.py | 47 + mmdet/datasets/builder.py | 185 ++ mmdet/datasets/cityscapes.py | 335 ++ mmdet/datasets/coco.py | 578 ++++ mmdet/datasets/coco_panoptic.py | 544 +++ mmdet/datasets/coco_pix2seq.py | 114 + mmdet/datasets/custom.py | 368 ++ mmdet/datasets/dataset_wrappers.py | 394 +++ mmdet/datasets/deepfashion.py | 11 + mmdet/datasets/lvis.py | 738 +++++ mmdet/datasets/pipelines/__init__.py | 28 + mmdet/datasets/pipelines/auto_augment.py | 894 +++++ mmdet/datasets/pipelines/compose.py | 52 + mmdet/datasets/pipelines/formating.py | 365 ++ mmdet/datasets/pipelines/instaboost.py | 118 + mmdet/datasets/pipelines/loading.py | 573 ++++ mmdet/datasets/pipelines/test_time_aug.py | 121 + mmdet/datasets/pipelines/transforms.py | 2945 +++++++++++++++++ mmdet/datasets/samplers/__init__.py | 9 + .../datasets/samplers/distributed_sampler.py | 40 + mmdet/datasets/samplers/group_sampler.py | 148 + mmdet/datasets/samplers/infinite_sampler.py | 171 + mmdet/datasets/utils.py | 168 + mmdet/datasets/voc.py | 105 + mmdet/datasets/wider_face.py | 52 + mmdet/datasets/xml_style.py | 178 + mmdet/models/__init__.py | 19 + mmdet/models/backbones/__init__.py | 24 + mmdet/models/backbones/csp_darknet.py | 284 ++ mmdet/models/backbones/darknet.py | 213 ++ mmdet/models/backbones/detectors_resnet.py | 353 ++ mmdet/models/backbones/detectors_resnext.py | 123 + mmdet/models/backbones/hourglass.py | 222 ++ mmdet/models/backbones/hrnet.py | 589 ++++ mmdet/models/backbones/mobilenet_v2.py | 197 ++ mmdet/models/backbones/pvt.py | 593 ++++ mmdet/models/backbones/regnet.py | 356 ++ mmdet/models/backbones/res2net.py | 327 ++ mmdet/models/backbones/resnest.py | 322 ++ mmdet/models/backbones/resnet.py | 671 ++++ mmdet/models/backbones/resnext.py | 154 + mmdet/models/backbones/ssd_vgg.py | 128 + mmdet/models/backbones/swin.py | 763 +++++ mmdet/models/backbones/trident_resnet.py | 298 ++ mmdet/models/builder.py | 59 + mmdet/models/dense_heads/__init__.py | 52 + mmdet/models/dense_heads/anchor_free_head.py | 350 ++ mmdet/models/dense_heads/anchor_head.py | 542 +++ mmdet/models/dense_heads/atss_head.py | 492 +++ mmdet/models/dense_heads/autoassign_head.py | 524 +++ mmdet/models/dense_heads/base_dense_head.py | 517 +++ mmdet/models/dense_heads/base_mask_head.py | 116 + mmdet/models/dense_heads/cascade_rpn_head.py | 801 +++++ mmdet/models/dense_heads/centernet_head.py | 412 +++ mmdet/models/dense_heads/centripetal_head.py | 427 +++ mmdet/models/dense_heads/corner_head.py | 1083 ++++++ .../dense_heads/deformable_detr_head.py | 318 ++ mmdet/models/dense_heads/dense_test_mixins.py | 206 ++ mmdet/models/dense_heads/detr_head.py | 822 +++++ .../models/dense_heads/embedding_rpn_head.py | 116 + mmdet/models/dense_heads/fcos_head.py | 453 +++ mmdet/models/dense_heads/fovea_head.py | 385 +++ .../dense_heads/free_anchor_retina_head.py | 271 ++ mmdet/models/dense_heads/fsaf_head.py | 433 +++ mmdet/models/dense_heads/ga_retina_head.py | 113 + mmdet/models/dense_heads/ga_rpn_head.py | 177 + mmdet/models/dense_heads/gfl_head.py | 648 ++++ .../models/dense_heads/guided_anchor_head.py | 868 +++++ mmdet/models/dense_heads/ld_head.py | 261 ++ mmdet/models/dense_heads/nasfcos_head.py | 80 + mmdet/models/dense_heads/paa_head.py | 756 +++++ .../models/dense_heads/pisa_retinanet_head.py | 155 + mmdet/models/dense_heads/pisa_ssd_head.py | 140 + mmdet/models/dense_heads/pix2seq_head.py | 430 +++ mmdet/models/dense_heads/reppoints_head.py | 764 +++++ mmdet/models/dense_heads/retina_head.py | 115 + mmdet/models/dense_heads/retina_sepbn_head.py | 118 + mmdet/models/dense_heads/rpn_head.py | 266 ++ mmdet/models/dense_heads/sabl_retina_head.py | 630 ++++ mmdet/models/dense_heads/solo_head.py | 1177 +++++++ mmdet/models/dense_heads/ssd_head.py | 357 ++ mmdet/models/dense_heads/vfnet_head.py | 740 +++++ mmdet/models/dense_heads/yolact_head.py | 1018 ++++++ mmdet/models/dense_heads/yolo_head.py | 619 ++++ mmdet/models/dense_heads/yolof_head.py | 416 +++ mmdet/models/dense_heads/yolox_head.py | 482 +++ mmdet/models/detectors/__init__.py | 51 + mmdet/models/detectors/atss.py | 19 + mmdet/models/detectors/autoassign.py | 19 + mmdet/models/detectors/base.py | 349 ++ mmdet/models/detectors/cascade_rcnn.py | 49 + mmdet/models/detectors/centernet.py | 111 + mmdet/models/detectors/cornernet.py | 97 + mmdet/models/detectors/deformable_detr.py | 10 + mmdet/models/detectors/detr.py | 116 + mmdet/models/detectors/fast_rcnn.py | 55 + mmdet/models/detectors/faster_rcnn.py | 27 + mmdet/models/detectors/fcos.py | 19 + mmdet/models/detectors/fovea.py | 19 + mmdet/models/detectors/fsaf.py | 19 + mmdet/models/detectors/gfl.py | 18 + mmdet/models/detectors/grid_rcnn.py | 32 + mmdet/models/detectors/htc.py | 16 + mmdet/models/detectors/kd_one_stage.py | 101 + mmdet/models/detectors/mask_rcnn.py | 27 + mmdet/models/detectors/mask_scoring_rcnn.py | 30 + mmdet/models/detectors/nasfcos.py | 22 + mmdet/models/detectors/paa.py | 19 + mmdet/models/detectors/panoptic_fpn.py | 34 + .../detectors/panoptic_two_stage_segmentor.py | 203 ++ mmdet/models/detectors/pix2seq.py | 45 + mmdet/models/detectors/point_rend.py | 32 + mmdet/models/detectors/queryinst.py | 27 + mmdet/models/detectors/reppoints_detector.py | 24 + mmdet/models/detectors/retinanet.py | 19 + mmdet/models/detectors/rpn.py | 159 + mmdet/models/detectors/scnet.py | 11 + mmdet/models/detectors/single_stage.py | 171 + .../detectors/single_stage_instance_seg.py | 363 ++ mmdet/models/detectors/solo.py | 29 + mmdet/models/detectors/sparse_rcnn.py | 111 + mmdet/models/detectors/trident_faster_rcnn.py | 70 + mmdet/models/detectors/two_stage.py | 211 ++ mmdet/models/detectors/vfnet.py | 20 + mmdet/models/detectors/yolact.py | 120 + mmdet/models/detectors/yolo.py | 42 + mmdet/models/detectors/yolof.py | 19 + mmdet/models/detectors/yolox.py | 20 + mmdet/models/losses/__init__.py | 32 + mmdet/models/losses/accuracy.py | 79 + mmdet/models/losses/ae_loss.py | 103 + mmdet/models/losses/balanced_l1_loss.py | 124 + mmdet/models/losses/cross_entropy_loss.py | 251 ++ mmdet/models/losses/dice_loss.py | 123 + mmdet/models/losses/focal_loss.py | 182 + mmdet/models/losses/gaussian_focal_loss.py | 92 + mmdet/models/losses/gfocal_loss.py | 189 ++ mmdet/models/losses/ghm_loss.py | 213 ++ mmdet/models/losses/iou_loss.py | 474 +++ mmdet/models/losses/kd_loss.py | 88 + mmdet/models/losses/mse_loss.py | 57 + mmdet/models/losses/pisa_loss.py | 184 + mmdet/models/losses/seesaw_loss.py | 262 ++ mmdet/models/losses/smooth_l1_loss.py | 146 + mmdet/models/losses/utils.py | 101 + mmdet/models/losses/varifocal_loss.py | 134 + mmdet/models/necks/__init__.py | 22 + mmdet/models/necks/bfp.py | 102 + mmdet/models/necks/channel_mapper.py | 100 + mmdet/models/necks/ct_resnet_neck.py | 94 + mmdet/models/necks/dilated_encoder.py | 108 + mmdet/models/necks/fpg.py | 406 +++ mmdet/models/necks/fpn.py | 203 ++ mmdet/models/necks/fpn_carafe.py | 275 ++ mmdet/models/necks/hrfpn.py | 100 + mmdet/models/necks/nas_fpn.py | 158 + mmdet/models/necks/nasfcos_fpn.py | 169 + mmdet/models/necks/pafpn.py | 158 + mmdet/models/necks/rfp.py | 135 + mmdet/models/necks/ssd_neck.py | 129 + mmdet/models/necks/yolo_neck.py | 140 + mmdet/models/necks/yolox_pafpn.py | 156 + mmdet/models/plugins/__init__.py | 4 + mmdet/models/plugins/dropblock.py | 85 + mmdet/models/roi_heads/__init__.py | 37 + mmdet/models/roi_heads/base_roi_head.py | 103 + mmdet/models/roi_heads/bbox_heads/__init__.py | 14 + .../models/roi_heads/bbox_heads/bbox_head.py | 593 ++++ .../roi_heads/bbox_heads/convfc_bbox_head.py | 228 ++ mmdet/models/roi_heads/bbox_heads/dii_head.py | 425 +++ .../roi_heads/bbox_heads/double_bbox_head.py | 178 + .../models/roi_heads/bbox_heads/sabl_head.py | 584 ++++ .../roi_heads/bbox_heads/scnet_bbox_head.py | 77 + mmdet/models/roi_heads/cascade_roi_head.py | 631 ++++ mmdet/models/roi_heads/double_roi_head.py | 34 + mmdet/models/roi_heads/dynamic_roi_head.py | 155 + mmdet/models/roi_heads/grid_roi_head.py | 170 + mmdet/models/roi_heads/htc_roi_head.py | 628 ++++ mmdet/models/roi_heads/mask_heads/__init__.py | 20 + .../roi_heads/mask_heads/coarse_mask_head.py | 100 + .../roi_heads/mask_heads/dynamic_mask_head.py | 146 + .../roi_heads/mask_heads/fcn_mask_head.py | 412 +++ .../mask_heads/feature_relay_head.py | 53 + .../mask_heads/fused_semantic_head.py | 117 + .../mask_heads/global_context_head.py | 101 + .../models/roi_heads/mask_heads/grid_head.py | 363 ++ .../roi_heads/mask_heads/htc_mask_head.py | 39 + .../roi_heads/mask_heads/mask_point_head.py | 306 ++ .../roi_heads/mask_heads/maskiou_head.py | 183 + .../roi_heads/mask_heads/scnet_mask_head.py | 28 + .../mask_heads/scnet_semantic_head.py | 28 + .../models/roi_heads/mask_scoring_roi_head.py | 113 + mmdet/models/roi_heads/pisa_roi_head.py | 160 + mmdet/models/roi_heads/point_rend_roi_head.py | 393 +++ .../roi_heads/roi_extractors/__init__.py | 6 + .../roi_extractors/base_roi_extractor.py | 88 + .../roi_extractors/generic_roi_extractor.py | 84 + .../single_level_roi_extractor.py | 115 + mmdet/models/roi_heads/scnet_roi_head.py | 605 ++++ .../models/roi_heads/shared_heads/__init__.py | 4 + .../roi_heads/shared_heads/res_layer.py | 80 + mmdet/models/roi_heads/sparse_roi_head.py | 424 +++ mmdet/models/roi_heads/standard_roi_head.py | 397 +++ mmdet/models/roi_heads/test_mixins.py | 311 ++ mmdet/models/roi_heads/trident_roi_head.py | 120 + mmdet/models/seg_heads/__init__.py | 3 + mmdet/models/seg_heads/base_semantic_head.py | 86 + mmdet/models/seg_heads/panoptic_fpn_head.py | 155 + .../panoptic_fusion_heads/__init__.py | 4 + .../base_panoptic_fusion_head.py | 48 + .../heuristic_fusion_head.py | 126 + mmdet/models/utils/__init__.py | 31 + mmdet/models/utils/brick_wrappers.py | 50 + mmdet/models/utils/builder.py | 47 + mmdet/models/utils/ckpt_convert.py | 137 + mmdet/models/utils/conv_upsample.py | 67 + mmdet/models/utils/csp_layer.py | 150 + mmdet/models/utils/gaussian_target.py | 268 ++ mmdet/models/utils/inverted_residual.py | 124 + mmdet/models/utils/make_divisible.py | 28 + mmdet/models/utils/misc.py | 42 + mmdet/models/utils/normed_predictor.py | 88 + mmdet/models/utils/positional_encoding.py | 163 + mmdet/models/utils/res_layer.py | 190 ++ mmdet/models/utils/se_layer.py | 58 + mmdet/models/utils/transformer.py | 2036 ++++++++++++ mmdet/models/utils/transformer_old.py | 2104 ++++++++++++ mmdet/utils/__init__.py | 5 + mmdet/utils/collect_env.py | 17 + mmdet/utils/contextmanagers.py | 122 + mmdet/utils/logger.py | 20 + mmdet/utils/profiling.py | 40 + mmdet/utils/util_mixins.py | 105 + mmdet/utils/util_random.py | 34 + mmdet/version.py | 19 + model-index.yml | 62 + pytest.ini | 7 + requirements.txt | 4 + requirements/build.txt | 3 + requirements/docs.txt | 7 + requirements/mminstall.txt | 1 + requirements/optional.txt | 4 + requirements/readthedocs.txt | 3 + requirements/runtime.txt | 6 + requirements/tests.txt | 14 + resources/000000212559.jpg | Bin 0 -> 173895 bytes resources/000000255664.jpg | Bin 0 -> 128199 bytes resources/000000289393.jpg | Bin 0 -> 106371 bytes resources/007114.jpg | Bin 0 -> 72599 bytes resources/007351.jpg | Bin 0 -> 77145 bytes resources/008322.jpg | Bin 0 -> 61937 bytes resources/coco_test_12510.jpg | Bin 0 -> 183096 bytes resources/corruptions_sev_3.png | Bin 0 -> 1401893 bytes resources/data_pipeline.png | Bin 0 -> 84111 bytes resources/loss_curve.png | Bin 0 -> 37484 bytes resources/mmdet-logo.png | Bin 0 -> 32836 bytes resources/qq_group_qrcode.jpg | Bin 0 -> 207584 bytes resources/vqvae-framework.png | Bin 0 -> 220943 bytes resources/zhihu_qrcode.jpg | Bin 0 -> 397245 bytes setup.cfg | 18 + setup.py | 217 ++ .../test_datasets/test_coco_dataset.py | 58 + tests/test_data/test_datasets/test_common.py | 364 ++ .../test_datasets/test_custom_dataset.py | 139 + .../test_datasets/test_dataset_wrapper.py | 142 + .../test_datasets/test_panoptic_dataset.py | 307 ++ .../test_datasets/test_xml_dataset.py | 23 + .../test_pipelines/test_formatting.py | 24 + .../test_data/test_pipelines/test_loading.py | 91 + .../test_data/test_pipelines/test_sampler.py | 329 ++ .../test_pipelines/test_transform/__init__.py | 4 + .../test_transform/test_img_augment.py | 174 + .../test_transform/test_models_aug_test.py | 131 + .../test_transform/test_rotate.py | 172 + .../test_transform/test_shear.py | 164 + .../test_transform/test_transform.py | 967 ++++++ .../test_transform/test_translate.py | 516 +++ .../test_pipelines/test_transform/utils.py | 78 + tests/test_data/test_utils.py | 80 + tests/test_downstream/test_mmtrack.py | 230 ++ tests/test_metrics/test_box_overlap.py | 134 + tests/test_metrics/test_losses.py | 241 ++ tests/test_metrics/test_mean_ap.py | 87 + tests/test_metrics/test_recall.py | 46 + tests/test_models/test_backbones/__init__.py | 4 + .../test_backbones/test_csp_darknet.py | 116 + .../test_backbones/test_detectors_resnet.py | 47 + .../test_backbones/test_hourglass.py | 49 + .../test_models/test_backbones/test_hrnet.py | 111 + .../test_backbones/test_mobilenet_v2.py | 173 + tests/test_models/test_backbones/test_pvt.py | 103 + .../test_models/test_backbones/test_regnet.py | 58 + .../test_models/test_backbones/test_renext.py | 105 + .../test_backbones/test_res2net.py | 62 + .../test_backbones/test_resnest.py | 47 + .../test_models/test_backbones/test_resnet.py | 632 ++++ tests/test_models/test_backbones/test_swin.py | 82 + .../test_backbones/test_trident_resnet.py | 180 + tests/test_models/test_backbones/utils.py | 32 + .../test_dense_heads/test_anchor_head.py | 70 + .../test_dense_heads/test_atss_head.py | 77 + .../test_dense_heads/test_autoassign_head.py | 91 + .../test_dense_heads/test_centernet_head.py | 107 + .../test_dense_heads/test_corner_head.py | 167 + .../test_dense_heads/test_dense_heads_attr.py | 44 + .../test_dense_heads/test_detr_head.py | 104 + .../test_dense_heads/test_fcos_head.py | 64 + .../test_dense_heads/test_fsaf_head.py | 82 + .../test_dense_heads/test_ga_anchor_head.py | 91 + .../test_dense_heads/test_gfl_head.py | 74 + .../test_dense_heads/test_ld_head.py | 121 + .../test_dense_heads/test_paa_head.py | 135 + .../test_dense_heads/test_pisa_head.py | 245 ++ .../test_dense_heads/test_sabl_retina_head.py | 76 + .../test_dense_heads/test_solo_head.py | 284 ++ .../test_dense_heads/test_vfnet_head.py | 63 + .../test_dense_heads/test_yolact_head.py | 137 + .../test_dense_heads/test_yolof_head.py | 76 + .../test_dense_heads/test_yolox_head.py | 72 + tests/test_models/test_forward.py | 672 ++++ tests/test_models/test_loss.py | 215 ++ tests/test_models/test_loss_compatibility.py | 201 ++ tests/test_models/test_necks.py | 406 +++ tests/test_models/test_plugins.py | 29 + tests/test_models/test_roi_heads/__init__.py | 4 + .../test_roi_heads/test_bbox_head.py | 251 ++ .../test_roi_heads/test_mask_head.py | 96 + .../test_roi_heads/test_roi_extractor.py | 114 + .../test_roi_heads/test_sabl_bbox_head.py | 77 + tests/test_models/test_roi_heads/utils.py | 38 + .../test_utils/test_brick_wrappers.py | 93 + .../test_utils/test_conv_upsample.py | 24 + .../test_utils/test_inverted_residual.py | 76 + .../test_models/test_utils/test_model_misc.py | 27 + .../test_utils/test_position_encoding.py | 39 + tests/test_models/test_utils/test_se_layer.py | 24 + .../test_utils/test_transformer.py | 569 ++++ tests/test_onnx/__init__.py | 4 + tests/test_onnx/test_head.py | 453 +++ tests/test_onnx/test_neck.py | 163 + tests/test_onnx/utils.py | 137 + tests/test_runtime/async_benchmark.py | 102 + tests/test_runtime/test_async.py | 83 + tests/test_runtime/test_config.py | 371 +++ tests/test_runtime/test_eval_hook.py | 252 ++ tests/test_runtime/test_fp16.py | 301 ++ tests/test_utils/test_anchor.py | 767 +++++ tests/test_utils/test_assigner.py | 498 +++ tests/test_utils/test_coder.py | 127 + tests/test_utils/test_general_data.py | 591 ++++ tests/test_utils/test_hook.py | 325 ++ tests/test_utils/test_masks.py | 689 ++++ tests/test_utils/test_misc.py | 162 + tests/test_utils/test_nms.py | 75 + tests/test_utils/test_version.py | 16 + tests/test_utils/test_visualization.py | 127 + tools/analysis_tools/analyze_logs.py | 180 + tools/analysis_tools/analyze_results.py | 199 ++ tools/analysis_tools/benchmark.py | 187 ++ tools/analysis_tools/coco_error_analysis.py | 339 ++ tools/analysis_tools/confusion_matrix.py | 261 ++ tools/analysis_tools/eval_metric.py | 80 + tools/analysis_tools/get_flops.py | 97 + tools/analysis_tools/optimize_anchors.py | 370 +++ tools/analysis_tools/robustness_eval.py | 251 ++ tools/analysis_tools/test_robustness.py | 387 +++ tools/dataset_converters/cityscapes.py | 152 + tools/dataset_converters/images2coco.py | 101 + tools/dataset_converters/pascal_voc.py | 237 ++ tools/deployment/mmdet2torchserve.py | 110 + tools/deployment/mmdet_handler.py | 71 + tools/deployment/onnx2tensorrt.py | 254 ++ tools/deployment/pytorch2onnx.py | 345 ++ tools/deployment/test.py | 143 + tools/deployment/test_torchserver.py | 74 + tools/dist_test.sh | 10 + tools/dist_train.sh | 8 + tools/misc/browse_dataset.py | 107 + tools/misc/print_config.py | 51 + tools/model_converters/detectron2pytorch.py | 83 + tools/model_converters/publish_model.py | 43 + tools/model_converters/regnet2mmdet.py | 90 + tools/model_converters/selfsup2mmdet.py | 42 + .../model_converters/upgrade_model_version.py | 210 ++ tools/model_converters/upgrade_ssd_version.py | 58 + tools/slurm_test.sh | 24 + tools/slurm_train.sh | 24 + tools/test.py | 234 ++ tools/train.py | 185 ++ 1273 files changed, 133851 insertions(+) create mode 100644 CITATION.cff create mode 100644 LICENSE create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 README_zh-CN.md create mode 100644 configs/_base_/datasets/cityscapes_detection.py create mode 100644 configs/_base_/datasets/cityscapes_instance.py create mode 100644 configs/_base_/datasets/coco_detection.py create mode 100644 configs/_base_/datasets/coco_detection_pix2seq.py create mode 100644 configs/_base_/datasets/coco_detection_vqvae.py create mode 100644 configs/_base_/datasets/coco_instance.py create mode 100644 configs/_base_/datasets/coco_instance_semantic.py create mode 100644 configs/_base_/datasets/coco_panoptic.py create mode 100644 configs/_base_/datasets/deepfashion.py create mode 100644 configs/_base_/datasets/lvis_v0.5_instance.py create mode 100644 configs/_base_/datasets/lvis_v1_instance.py create mode 100644 configs/_base_/datasets/voc0712.py create mode 100644 configs/_base_/datasets/voc0712_pix2seq.py create mode 100644 configs/_base_/datasets/wider_face.py create mode 100644 configs/_base_/default_runtime.py create mode 100644 configs/_base_/models/cascade_mask_rcnn_r50_fpn.py create mode 100644 configs/_base_/models/cascade_rcnn_r50_fpn.py create mode 100644 configs/_base_/models/fast_rcnn_r50_fpn.py create mode 100644 configs/_base_/models/faster_rcnn_r50_caffe_c4.py create mode 100644 configs/_base_/models/faster_rcnn_r50_caffe_dc5.py create mode 100644 configs/_base_/models/faster_rcnn_r50_fpn.py create mode 100644 configs/_base_/models/mask_rcnn_r50_caffe_c4.py create mode 100644 configs/_base_/models/mask_rcnn_r50_fpn.py create mode 100644 configs/_base_/models/retinanet_r50_fpn.py create mode 100644 configs/_base_/models/rpn_r50_caffe_c4.py create mode 100644 configs/_base_/models/rpn_r50_fpn.py create mode 100644 configs/_base_/models/ssd300.py create mode 100644 configs/_base_/schedules/schedule_1x.py create mode 100644 configs/_base_/schedules/schedule_20e.py create mode 100644 configs/_base_/schedules/schedule_2x.py create mode 100644 configs/albu_example/README.md create mode 100644 configs/albu_example/mask_rcnn_r50_fpn_albu_1x_coco.py create mode 100644 configs/atss/README.md create mode 100644 configs/atss/atss_r101_fpn_1x_coco.py create mode 100644 configs/atss/atss_r50_fpn_1x_coco.py create mode 100644 configs/atss/metafile.yml create mode 100644 configs/autoassign/README.md create mode 100644 configs/autoassign/autoassign_r50_fpn_8x2_1x_coco.py create mode 100644 configs/autoassign/metafile.yml create mode 100644 configs/carafe/README.md create mode 100644 configs/carafe/faster_rcnn_r50_fpn_carafe_1x_coco.py create mode 100644 configs/carafe/mask_rcnn_r50_fpn_carafe_1x_coco.py create mode 100644 configs/cascade_rcnn/README.md create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco.py create mode 100644 configs/cascade_rcnn/metafile.yml create mode 100644 configs/cascade_rpn/README.md create mode 100644 configs/cascade_rpn/crpn_fast_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/cascade_rpn/crpn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/centernet/README.md create mode 100644 configs/centernet/centernet_resnet18_140e_coco.py create mode 100644 configs/centernet/centernet_resnet18_dcnv2_140e_coco.py create mode 100644 configs/centernet/metafile.yml create mode 100644 configs/centripetalnet/README.md create mode 100644 configs/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco.py create mode 100644 configs/centripetalnet/metafile.yml create mode 100644 configs/cityscapes/README.md create mode 100644 configs/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes.py create mode 100644 configs/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes.py create mode 100644 configs/common/lsj_100e_coco_instance.py create mode 100644 configs/common/mstrain-poly_3x_coco_instance.py create mode 100644 configs/common/mstrain_3x_coco.py create mode 100644 configs/common/mstrain_3x_coco_instance.py create mode 100644 configs/cornernet/README.md create mode 100644 configs/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco.py create mode 100644 configs/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco.py create mode 100644 configs/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco.py create mode 100644 configs/cornernet/metafile.yml create mode 100644 configs/dcn/README.md create mode 100644 configs/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py create mode 100644 configs/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py create mode 100644 configs/dcn/metafile.yml create mode 100644 configs/deepfashion/README.md create mode 100644 configs/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion.py create mode 100644 configs/deformable_detr/README.md create mode 100644 configs/deformable_detr/deformable_detr_r50_16x2_50e_coco.py create mode 100644 configs/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco.py create mode 100644 configs/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco.py create mode 100644 configs/deformable_detr/metafile.yml create mode 100644 configs/detectors/README.md create mode 100644 configs/detectors/cascade_rcnn_r50_rfp_1x_coco.py create mode 100644 configs/detectors/cascade_rcnn_r50_sac_1x_coco.py create mode 100644 configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py create mode 100644 configs/detectors/detectors_htc_r101_20e_coco.py create mode 100644 configs/detectors/detectors_htc_r50_1x_coco.py create mode 100644 configs/detectors/htc_r50_rfp_1x_coco.py create mode 100644 configs/detectors/htc_r50_sac_1x_coco.py create mode 100644 configs/detectors/metafile.yml create mode 100644 configs/detr/README.md create mode 100644 configs/detr/detr_r50_8x2_150e_coco.py create mode 100644 configs/detr/detr_r50_8x2_150e_coco_merge.py create mode 100644 configs/detr/metafile.yml create mode 100644 configs/double_heads/README.md create mode 100644 configs/double_heads/dh_faster_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/double_heads/metafile.yml create mode 100644 configs/dynamic_rcnn/README.md create mode 100644 configs/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/dynamic_rcnn/metafile.yml create mode 100644 configs/empirical_attention/README.md create mode 100644 configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco.py create mode 100644 configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco.py create mode 100644 configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco.py create mode 100644 configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco.py create mode 100644 configs/empirical_attention/metafile.yml create mode 100644 configs/fast_rcnn/README.md create mode 100644 configs/fast_rcnn/fast_rcnn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/fast_rcnn/fast_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/fast_rcnn/fast_rcnn_r101_fpn_2x_coco.py create mode 100644 configs/fast_rcnn/fast_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/fast_rcnn/fast_rcnn_r50_fpn_2x_coco.py create mode 100644 configs/faster_rcnn/README.md create mode 100644 configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_c4_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_90k_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person-bicycle-car.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_90k_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_bounded_iou_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_ciou_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_giou_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_iou_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_ohem_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_r50_fpn_soft_nms_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco.py create mode 100644 configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py create mode 100644 configs/faster_rcnn/metafile.yml create mode 100644 configs/fcos/README.md create mode 100644 configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco.py create mode 100644 configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py create mode 100644 configs/fcos/fcos_center_r50_caffe_fpn_gn-head_1x_coco.py create mode 100644 configs/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco.py create mode 100644 configs/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py create mode 100644 configs/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco.py create mode 100644 configs/fcos/fcos_r50_caffe_fpn_gn-head_4x4_1x_coco.py create mode 100644 configs/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py create mode 100644 configs/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco.py create mode 100644 configs/fcos/metafile.yml create mode 100644 configs/foveabox/README.md create mode 100644 configs/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco.py create mode 100644 configs/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py create mode 100644 configs/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco.py create mode 100644 configs/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py create mode 100644 configs/foveabox/fovea_r101_fpn_4x4_1x_coco.py create mode 100644 configs/foveabox/fovea_r101_fpn_4x4_2x_coco.py create mode 100644 configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py create mode 100644 configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py create mode 100644 configs/foveabox/metafile.yml create mode 100644 configs/fp16/README.md create mode 100644 configs/fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py create mode 100644 configs/fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py create mode 100644 configs/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py create mode 100644 configs/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py create mode 100644 configs/fp16/metafile.yml create mode 100644 configs/fp16/retinanet_r50_fpn_fp16_1x_coco.py create mode 100644 configs/fpg/README.md create mode 100644 configs/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco.py create mode 100644 configs/fpg/faster_rcnn_r50_fpg_crop640_50e_coco.py create mode 100644 configs/fpg/faster_rcnn_r50_fpn_crop640_50e_coco.py create mode 100644 configs/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco.py create mode 100644 configs/fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py create mode 100644 configs/fpg/mask_rcnn_r50_fpn_crop640_50e_coco.py create mode 100644 configs/fpg/metafile.yml create mode 100644 configs/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco.py create mode 100644 configs/fpg/retinanet_r50_fpg_crop640_50e_coco.py create mode 100644 configs/free_anchor/README.md create mode 100644 configs/free_anchor/metafile.yml create mode 100644 configs/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco.py create mode 100644 configs/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco.py create mode 100644 configs/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/fsaf/README.md create mode 100644 configs/fsaf/fsaf_r101_fpn_1x_coco.py create mode 100644 configs/fsaf/fsaf_r50_fpn_1x_coco.py create mode 100644 configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/fsaf/metafile.yml create mode 100644 configs/gcnet/README.md create mode 100644 configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py create mode 100644 configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py create mode 100644 configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py create mode 100644 configs/gcnet/metafile.yml create mode 100644 configs/gfl/README.md create mode 100644 configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py create mode 100644 configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py create mode 100644 configs/gfl/gfl_r50_fpn_1x_coco.py create mode 100644 configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py create mode 100644 configs/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py create mode 100644 configs/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py create mode 100644 configs/gfl/metafile.yml create mode 100644 configs/ghm/README.md create mode 100644 configs/ghm/metafile.yml create mode 100644 configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py create mode 100644 configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py create mode 100644 configs/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/gn+ws/README.md create mode 100644 configs/gn+ws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py create mode 100644 configs/gn+ws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py create mode 100644 configs/gn+ws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py create mode 100644 configs/gn+ws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py create mode 100644 configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py create mode 100644 configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py create mode 100644 configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py create mode 100644 configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py create mode 100644 configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py create mode 100644 configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py create mode 100644 configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py create mode 100644 configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py create mode 100644 configs/gn+ws/metafile.yml create mode 100644 configs/gn/README.md create mode 100644 configs/gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py create mode 100644 configs/gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py create mode 100644 configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py create mode 100644 configs/gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py create mode 100644 configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py create mode 100644 configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py create mode 100644 configs/gn/metafile.yml create mode 100644 configs/grid_rcnn/README.md create mode 100644 configs/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco.py create mode 100644 configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_1x_coco.py create mode 100644 configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco.py create mode 100644 configs/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py create mode 100644 configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py create mode 100644 configs/grid_rcnn/metafile.yml create mode 100644 configs/groie/README.md create mode 100644 configs/groie/faster_rcnn_r50_fpn_groie_1x_coco.py create mode 100644 configs/groie/grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py create mode 100644 configs/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py create mode 100644 configs/groie/mask_rcnn_r50_fpn_groie_1x_coco.py create mode 100644 configs/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py create mode 100644 configs/groie/metafile.yml create mode 100644 configs/guided_anchoring/README.md create mode 100644 configs/guided_anchoring/ga_fast_r50_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_faster_r50_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_mstrain_2x.py create mode 100644 configs/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_retinanet_r50_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_rpn_r50_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/guided_anchoring/metafile.yml create mode 100644 configs/hrnet/README.md create mode 100644 configs/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py create mode 100644 configs/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py create mode 100644 configs/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py create mode 100644 configs/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco.py create mode 100644 configs/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco.py create mode 100644 configs/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco.py create mode 100644 configs/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py create mode 100644 configs/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py create mode 100644 configs/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py create mode 100644 configs/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py create mode 100644 configs/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py create mode 100644 configs/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py create mode 100644 configs/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco.py create mode 100644 configs/hrnet/htc_hrnetv2p_w18_20e_coco.py create mode 100644 configs/hrnet/htc_hrnetv2p_w32_20e_coco.py create mode 100644 configs/hrnet/htc_hrnetv2p_w40_20e_coco.py create mode 100644 configs/hrnet/htc_hrnetv2p_w40_28e_coco.py create mode 100644 configs/hrnet/htc_x101_64x4d_fpn_16x1_28e_coco.py create mode 100644 configs/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py create mode 100644 configs/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py create mode 100644 configs/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py create mode 100644 configs/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py create mode 100644 configs/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py create mode 100644 configs/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py create mode 100644 configs/hrnet/metafile.yml create mode 100644 configs/htc/README.md create mode 100644 configs/htc/htc_r101_fpn_20e_coco.py create mode 100644 configs/htc/htc_r50_fpn_1x_coco.py create mode 100644 configs/htc/htc_r50_fpn_20e_coco.py create mode 100644 configs/htc/htc_without_semantic_r50_fpn_1x_coco.py create mode 100644 configs/htc/htc_x101_32x4d_fpn_16x1_20e_coco.py create mode 100644 configs/htc/htc_x101_64x4d_fpn_16x1_20e_coco.py create mode 100644 configs/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco.py create mode 100644 configs/htc/metafile.yml create mode 100644 configs/instaboost/README.md create mode 100644 configs/instaboost/cascade_mask_rcnn_r101_fpn_instaboost_4x_coco.py create mode 100644 configs/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py create mode 100644 configs/instaboost/cascade_mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py create mode 100644 configs/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco.py create mode 100644 configs/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco.py create mode 100644 configs/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py create mode 100644 configs/instaboost/metafile.yml create mode 100644 configs/ld/README.md create mode 100644 configs/ld/ld_r101_gflv1_r101dcn_fpn_coco_2x.py create mode 100644 configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py create mode 100644 configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py create mode 100644 configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py create mode 100644 configs/ld/metafile.yml create mode 100644 configs/legacy_1.x/README.md create mode 100644 configs/legacy_1.x/cascade_mask_rcnn_r50_fpn_1x_coco_v1.py create mode 100644 configs/legacy_1.x/faster_rcnn_r50_fpn_1x_coco_v1.py create mode 100644 configs/legacy_1.x/mask_rcnn_r50_fpn_1x_coco_v1.py create mode 100644 configs/legacy_1.x/retinanet_r50_caffe_fpn_1x_coco_v1.py create mode 100644 configs/legacy_1.x/retinanet_r50_fpn_1x_coco_v1.py create mode 100644 configs/legacy_1.x/ssd300_coco_v1.py create mode 100644 configs/libra_rcnn/README.md create mode 100644 configs/libra_rcnn/libra_fast_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/libra_rcnn/libra_retinanet_r50_fpn_1x_coco.py create mode 100644 configs/libra_rcnn/metafile.yml create mode 100644 configs/lvis/README.md create mode 100644 configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1.py create mode 100644 configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py create mode 100644 configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py create mode 100644 configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py create mode 100644 configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py create mode 100644 configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py create mode 100644 configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py create mode 100644 configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py create mode 100644 configs/mask_rcnn/README.md create mode 100644 configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_c4_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_poly_1x_coco_v1.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_r50_fpn_poly_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco.py create mode 100644 configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/mask_rcnn/metafile.yml create mode 100644 configs/ms_rcnn/README.md create mode 100644 configs/ms_rcnn/metafile.yml create mode 100644 configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py create mode 100644 configs/nas_fcos/README.md create mode 100644 configs/nas_fcos/metafile.yml create mode 100644 configs/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco.py create mode 100644 configs/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco.py create mode 100644 configs/nas_fpn/README.md create mode 100644 configs/nas_fpn/metafile.yml create mode 100644 configs/nas_fpn/retinanet_r50_fpn_crop640_50e_coco.py create mode 100644 configs/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py create mode 100644 configs/paa/README.md create mode 100644 configs/paa/metafile.yml create mode 100644 configs/paa/paa_r101_fpn_1x_coco.py create mode 100644 configs/paa/paa_r101_fpn_2x_coco.py create mode 100644 configs/paa/paa_r101_fpn_mstrain_3x_coco.py create mode 100644 configs/paa/paa_r50_fpn_1.5x_coco.py create mode 100644 configs/paa/paa_r50_fpn_1x_coco.py create mode 100644 configs/paa/paa_r50_fpn_2x_coco.py create mode 100644 configs/paa/paa_r50_fpn_mstrain_3x_coco.py create mode 100644 configs/pafpn/README.md create mode 100644 configs/pafpn/faster_rcnn_r50_pafpn_1x_coco.py create mode 100644 configs/pafpn/metafile.yml create mode 100644 configs/panoptic_fpn/README.md create mode 100644 configs/panoptic_fpn/metafile.yml create mode 100644 configs/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco.py create mode 100644 configs/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco.py create mode 100644 configs/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco.py create mode 100644 configs/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco.py create mode 100644 configs/pascal_voc/README.md create mode 100644 configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712.py create mode 100644 configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712_cocofmt.py create mode 100644 configs/pascal_voc/retinanet_r50_fpn_1x_voc0712.py create mode 100644 configs/pascal_voc/ssd300_voc0712.py create mode 100644 configs/pascal_voc/ssd512_voc0712.py create mode 100644 configs/pisa/README.md create mode 100644 configs/pisa/metafile.yml create mode 100644 configs/pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/pisa/pisa_mask_rcnn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/pisa/pisa_retinanet_r50_fpn_1x_coco.py create mode 100644 configs/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/pisa/pisa_ssd300_coco.py create mode 100644 configs/pisa/pisa_ssd512_coco.py create mode 100644 configs/pix2seq/README.md create mode 100644 configs/pix2seq/metafile.yml create mode 100644 configs/pix2seq/pix2seq_r50_8x4_300e_coco.py create mode 100644 configs/point_rend/README.md create mode 100644 configs/point_rend/metafile.yml create mode 100644 configs/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco.py create mode 100644 configs/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/pvt/README.md create mode 100644 configs/pvt/metafile.yml create mode 100644 configs/pvt/retinanet_pvt-l_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvt-m_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvt-s_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvt-t_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvtv2-b0_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvtv2-b1_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvtv2-b2_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvtv2-b3_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvtv2-b4_fpn_1x_coco.py create mode 100644 configs/pvt/retinanet_pvtv2-b5_fpn_1x_coco.py create mode 100644 configs/queryinst/README.md create mode 100644 configs/queryinst/metafile.yml create mode 100644 configs/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py create mode 100644 configs/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco.py create mode 100644 configs/queryinst/queryinst_r50_fpn_1x_coco.py create mode 100644 configs/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py create mode 100644 configs/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco.py create mode 100644 configs/regnet/README.md create mode 100644 configs/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco.py create mode 100644 configs/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco.py create mode 100644 configs/regnet/metafile.yml create mode 100644 configs/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco.py create mode 100644 configs/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco.py create mode 100644 configs/regnet/retinanet_regnetx-800MF_fpn_1x_coco.py create mode 100644 configs/reppoints/README.md create mode 100644 configs/reppoints/bbox_r50_grid_center_fpn_gn-neck+head_1x_coco.py create mode 100644 configs/reppoints/bbox_r50_grid_fpn_gn-neck+head_1x_coco.py create mode 100644 configs/reppoints/metafile.yml create mode 100644 configs/reppoints/reppoints.png create mode 100644 configs/reppoints/reppoints_minmax_r50_fpn_gn-neck+head_1x_coco.py create mode 100644 configs/reppoints/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py create mode 100644 configs/reppoints/reppoints_moment_r101_fpn_gn-neck+head_2x_coco.py create mode 100644 configs/reppoints/reppoints_moment_r50_fpn_1x_coco.py create mode 100644 configs/reppoints/reppoints_moment_r50_fpn_gn-neck+head_1x_coco.py create mode 100644 configs/reppoints/reppoints_moment_r50_fpn_gn-neck+head_2x_coco.py create mode 100644 configs/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py create mode 100644 configs/reppoints/reppoints_partial_minmax_r50_fpn_gn-neck+head_1x_coco.py create mode 100644 configs/res2net/README.md create mode 100644 configs/res2net/cascade_mask_rcnn_r2_101_fpn_20e_coco.py create mode 100644 configs/res2net/cascade_rcnn_r2_101_fpn_20e_coco.py create mode 100644 configs/res2net/faster_rcnn_r2_101_fpn_2x_coco.py create mode 100644 configs/res2net/htc_r2_101_fpn_20e_coco.py create mode 100644 configs/res2net/mask_rcnn_r2_101_fpn_2x_coco.py create mode 100644 configs/res2net/metafile.yml create mode 100644 configs/resnest/README.md create mode 100644 configs/resnest/cascade_mask_rcnn_s101_fpn_syncbn-backbone+head_mstrain_1x_coco.py create mode 100644 configs/resnest/cascade_mask_rcnn_s50_fpn_syncbn-backbone+head_mstrain_1x_coco.py create mode 100644 configs/resnest/cascade_rcnn_s101_fpn_syncbn-backbone+head_mstrain-range_1x_coco.py create mode 100644 configs/resnest/cascade_rcnn_s50_fpn_syncbn-backbone+head_mstrain-range_1x_coco.py create mode 100644 configs/resnest/faster_rcnn_s101_fpn_syncbn-backbone+head_mstrain-range_1x_coco.py create mode 100644 configs/resnest/faster_rcnn_s50_fpn_syncbn-backbone+head_mstrain-range_1x_coco.py create mode 100644 configs/resnest/mask_rcnn_s101_fpn_syncbn-backbone+head_mstrain_1x_coco.py create mode 100644 configs/resnest/mask_rcnn_s50_fpn_syncbn-backbone+head_mstrain_1x_coco.py create mode 100644 configs/resnest/metafile.yml create mode 100644 configs/retinanet/README.md create mode 100644 configs/retinanet/metafile.yml create mode 100644 configs/retinanet/retinanet_r101_caffe_fpn_1x_coco.py create mode 100644 configs/retinanet/retinanet_r101_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/retinanet/retinanet_r101_fpn_1x_coco.py create mode 100644 configs/retinanet/retinanet_r101_fpn_2x_coco.py create mode 100644 configs/retinanet/retinanet_r101_fpn_mstrain_640-800_3x_coco.py create mode 100644 configs/retinanet/retinanet_r50_caffe_fpn_1x_coco.py create mode 100644 configs/retinanet/retinanet_r50_caffe_fpn_mstrain_1x_coco.py create mode 100644 configs/retinanet/retinanet_r50_caffe_fpn_mstrain_2x_coco.py create mode 100644 configs/retinanet/retinanet_r50_caffe_fpn_mstrain_3x_coco.py create mode 100644 configs/retinanet/retinanet_r50_fpn_1x_coco.py create mode 100644 configs/retinanet/retinanet_r50_fpn_2x_coco.py create mode 100644 configs/retinanet/retinanet_r50_fpn_90k_coco.py create mode 100644 configs/retinanet/retinanet_r50_fpn_mstrain_640-800_3x_coco.py create mode 100644 configs/retinanet/retinanet_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/retinanet/retinanet_x101_32x4d_fpn_2x_coco.py create mode 100644 configs/retinanet/retinanet_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/retinanet/retinanet_x101_64x4d_fpn_2x_coco.py create mode 100644 configs/retinanet/retinanet_x101_64x4d_fpn_mstrain_640-800_3x_coco.py create mode 100644 configs/rpn/README.md create mode 100644 configs/rpn/rpn_r101_caffe_fpn_1x_coco.py create mode 100644 configs/rpn/rpn_r101_fpn_1x_coco.py create mode 100644 configs/rpn/rpn_r101_fpn_2x_coco.py create mode 100644 configs/rpn/rpn_r50_caffe_c4_1x_coco.py create mode 100644 configs/rpn/rpn_r50_caffe_fpn_1x_coco.py create mode 100644 configs/rpn/rpn_r50_fpn_1x_coco.py create mode 100644 configs/rpn/rpn_r50_fpn_2x_coco.py create mode 100644 configs/rpn/rpn_x101_32x4d_fpn_1x_coco.py create mode 100644 configs/rpn/rpn_x101_32x4d_fpn_2x_coco.py create mode 100644 configs/rpn/rpn_x101_64x4d_fpn_1x_coco.py create mode 100644 configs/rpn/rpn_x101_64x4d_fpn_2x_coco.py create mode 100644 configs/sabl/README.md create mode 100644 configs/sabl/metafile.yml create mode 100644 configs/sabl/sabl_cascade_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/sabl/sabl_cascade_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/sabl/sabl_faster_rcnn_r101_fpn_1x_coco.py create mode 100644 configs/sabl/sabl_faster_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/sabl/sabl_retinanet_r101_fpn_1x_coco.py create mode 100644 configs/sabl/sabl_retinanet_r101_fpn_gn_1x_coco.py create mode 100644 configs/sabl/sabl_retinanet_r101_fpn_gn_2x_ms_480_960_coco.py create mode 100644 configs/sabl/sabl_retinanet_r101_fpn_gn_2x_ms_640_800_coco.py create mode 100644 configs/sabl/sabl_retinanet_r50_fpn_1x_coco.py create mode 100644 configs/sabl/sabl_retinanet_r50_fpn_gn_1x_coco.py create mode 100644 configs/scnet/README.md create mode 100644 configs/scnet/metafile.yml create mode 100644 configs/scnet/scnet_r101_fpn_20e_coco.py create mode 100644 configs/scnet/scnet_r50_fpn_1x_coco.py create mode 100644 configs/scnet/scnet_r50_fpn_20e_coco.py create mode 100644 configs/scnet/scnet_x101_64x4d_fpn_20e_coco.py create mode 100644 configs/scnet/scnet_x101_64x4d_fpn_8x1_20e_coco.py create mode 100644 configs/scratch/README.md create mode 100644 configs/scratch/faster_rcnn_r50_fpn_gn-all_scratch_6x_coco.py create mode 100644 configs/scratch/mask_rcnn_r50_fpn_gn-all_scratch_6x_coco.py create mode 100644 configs/scratch/metafile.yml create mode 100644 configs/seesaw_loss/README.md create mode 100644 configs/seesaw_loss/cascade_mask_rcnn_r101_fpn_random_seesaw_loss_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/cascade_mask_rcnn_r101_fpn_random_seesaw_loss_normed_mask_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/cascade_mask_rcnn_r101_fpn_sample1e-3_seesaw_loss_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/cascade_mask_rcnn_r101_fpn_sample1e-3_seesaw_loss_normed_mask_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r101_fpn_random_seesaw_loss_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r101_fpn_random_seesaw_loss_normed_mask_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r101_fpn_sample1e-3_seesaw_loss_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r101_fpn_sample1e-3_seesaw_loss_normed_mask_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r50_fpn_random_seesaw_loss_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r50_fpn_random_seesaw_loss_normed_mask_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r50_fpn_sample1e-3_seesaw_loss_mstrain_2x_lvis_v1.py create mode 100644 configs/seesaw_loss/mask_rcnn_r50_fpn_sample1e-3_seesaw_loss_normed_mask_mstrain_2x_lvis_v1.py create mode 100644 configs/selfsup_pretrain/README.md create mode 100644 configs/selfsup_pretrain/mask_rcnn_r50_fpn_mocov2-pretrain_1x_coco.py create mode 100644 configs/selfsup_pretrain/mask_rcnn_r50_fpn_mocov2-pretrain_ms-2x_coco.py create mode 100644 configs/selfsup_pretrain/mask_rcnn_r50_fpn_swav-pretrain_1x_coco.py create mode 100644 configs/selfsup_pretrain/mask_rcnn_r50_fpn_swav-pretrain_ms-2x_coco.py create mode 100644 configs/solo/README.md create mode 100644 configs/solo/decoupled_solo_light_r50_fpn_3x_coco.py create mode 100644 configs/solo/decoupled_solo_r50_fpn_1x_coco.py create mode 100644 configs/solo/decoupled_solo_r50_fpn_3x_coco.py create mode 100644 configs/solo/metafile.yml create mode 100644 configs/solo/solo_r50_fpn_1x_coco.py create mode 100644 configs/solo/solo_r50_fpn_3x_coco.py create mode 100644 configs/sparse_rcnn/README.md create mode 100644 configs/sparse_rcnn/metafile.yml create mode 100644 configs/sparse_rcnn/sparse_rcnn_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py create mode 100644 configs/sparse_rcnn/sparse_rcnn_r101_fpn_mstrain_480-800_3x_coco.py create mode 100644 configs/sparse_rcnn/sparse_rcnn_r50_fpn_1x_coco.py create mode 100644 configs/sparse_rcnn/sparse_rcnn_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py create mode 100644 configs/sparse_rcnn/sparse_rcnn_r50_fpn_mstrain_480-800_3x_coco.py create mode 100644 configs/ssd/README.md create mode 100644 configs/ssd/metafile.yml create mode 100644 configs/ssd/ssd300_coco.py create mode 100644 configs/ssd/ssd512_coco.py create mode 100644 configs/ssd/ssdlite_mobilenetv2_scratch_600e_coco.py create mode 100644 configs/strong_baselines/README.md create mode 100644 configs/strong_baselines/mask_rcnn_r50_caffe_fpn_syncbn-all_rpn-2conv_lsj_100e_coco.py create mode 100644 configs/strong_baselines/mask_rcnn_r50_caffe_fpn_syncbn-all_rpn-2conv_lsj_100e_fp16_coco.py create mode 100644 configs/strong_baselines/mask_rcnn_r50_caffe_fpn_syncbn-all_rpn-2conv_lsj_400e_coco.py create mode 100644 configs/strong_baselines/mask_rcnn_r50_fpn_syncbn-all_rpn-2conv_lsj_100e_coco.py create mode 100644 configs/strong_baselines/mask_rcnn_r50_fpn_syncbn-all_rpn-2conv_lsj_100e_fp16_coco.py create mode 100644 configs/strong_baselines/mask_rcnn_r50_fpn_syncbn-all_rpn-2conv_lsj_50e_coco.py create mode 100644 configs/swin/README.md create mode 100644 configs/swin/mask_rcnn_swin-s-p4-w7_fpn_fp16_ms-crop-3x_coco.py create mode 100644 configs/swin/mask_rcnn_swin-t-p4-w7_fpn_1x_coco.py create mode 100644 configs/swin/mask_rcnn_swin-t-p4-w7_fpn_fp16_ms-crop-3x_coco.py create mode 100644 configs/swin/mask_rcnn_swin-t-p4-w7_fpn_ms-crop-3x_coco.py create mode 100644 configs/swin/metafile.yml create mode 100644 configs/tridentnet/README.md create mode 100644 configs/tridentnet/metafile.yml create mode 100644 configs/tridentnet/tridentnet_r50_caffe_1x_coco.py create mode 100644 configs/tridentnet/tridentnet_r50_caffe_mstrain_1x_coco.py create mode 100644 configs/tridentnet/tridentnet_r50_caffe_mstrain_3x_coco.py create mode 100644 configs/vfnet/README.md create mode 100644 configs/vfnet/metafile.yml create mode 100644 configs/vfnet/vfnet_r101_fpn_1x_coco.py create mode 100644 configs/vfnet/vfnet_r101_fpn_2x_coco.py create mode 100644 configs/vfnet/vfnet_r101_fpn_mdconv_c3-c5_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_r101_fpn_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_r2_101_fpn_mdconv_c3-c5_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_r2_101_fpn_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_r50_fpn_1x_coco.py create mode 100644 configs/vfnet/vfnet_r50_fpn_mdconv_c3-c5_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_r50_fpn_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_x101_32x4d_fpn_mdconv_c3-c5_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_x101_32x4d_fpn_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_x101_64x4d_fpn_mdconv_c3-c5_mstrain_2x_coco.py create mode 100644 configs/vfnet/vfnet_x101_64x4d_fpn_mstrain_2x_coco.py create mode 100644 configs/wider_face/README.md create mode 100644 configs/wider_face/ssd300_wider_face.py create mode 100644 configs/yolact/README.md create mode 100644 configs/yolact/metafile.yml create mode 100644 configs/yolact/yolact_r101_1x8_coco.py create mode 100644 configs/yolact/yolact_r50_1x8_coco.py create mode 100644 configs/yolact/yolact_r50_8x8_coco.py create mode 100644 configs/yolo/README.md create mode 100644 configs/yolo/metafile.yml create mode 100644 configs/yolo/yolov3_d53_320_273e_coco.py create mode 100644 configs/yolo/yolov3_d53_fp16_mstrain-608_273e_coco.py create mode 100644 configs/yolo/yolov3_d53_mstrain-416_273e_coco.py create mode 100644 configs/yolo/yolov3_d53_mstrain-608_273e_coco.py create mode 100644 configs/yolo/yolov3_mobilenetv2_320_300e_coco.py create mode 100644 configs/yolo/yolov3_mobilenetv2_mstrain-416_300e_coco.py create mode 100644 configs/yolof/README.md create mode 100644 configs/yolof/metafile.yml create mode 100644 configs/yolof/yolof_r50_c5_8x8_1x_coco.py create mode 100644 configs/yolof/yolof_r50_c5_8x8_iter-1x_coco.py create mode 100644 configs/yolox/README.md create mode 100644 configs/yolox/metafile.yml create mode 100644 configs/yolox/yolox_l_8x8_300e_coco.py create mode 100644 configs/yolox/yolox_m_8x8_300e_coco.py create mode 100644 configs/yolox/yolox_nano_8x8_300e_coco.py create mode 100644 configs/yolox/yolox_s_8x8_300e_coco.py create mode 100644 configs/yolox/yolox_tiny_8x8_300e_coco.py create mode 100644 configs/yolox/yolox_x_8x8_300e_coco.py create mode 100644 demo/MMDet_Tutorial.ipynb create mode 100644 demo/create_result_gif.py create mode 100644 demo/demo.jpg create mode 100644 demo/demo.mp4 create mode 100644 demo/image_demo.py create mode 100644 demo/inference_demo.ipynb create mode 100644 demo/video_demo.py create mode 100644 demo/webcam_demo.py create mode 100644 docker/Dockerfile create mode 100644 docker/serve/Dockerfile create mode 100644 docker/serve/config.properties create mode 100644 docker/serve/entrypoint.sh create mode 100644 docs/1_exist_data_model.md create mode 100644 docs/2_new_data_model.md create mode 100644 docs/3_exist_data_new_model.md create mode 100644 docs/Makefile create mode 100644 docs/_static/css/readthedocs.css create mode 100644 docs/_static/image/mmdet-logo.png create mode 100644 docs/api.rst create mode 100644 docs/changelog.md create mode 100644 docs/compatibility.md create mode 100644 docs/conf.py create mode 100644 docs/conventions.md create mode 100644 docs/faq.md create mode 100644 docs/get_started.md create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/model_zoo.md create mode 100644 docs/projects.md create mode 100644 docs/robustness_benchmarking.md create mode 100644 docs/stat.py create mode 100644 docs/switch_language.md create mode 100644 docs/tutorials/config.md create mode 100644 docs/tutorials/customize_dataset.md create mode 100644 docs/tutorials/customize_losses.md create mode 100644 docs/tutorials/customize_models.md create mode 100644 docs/tutorials/customize_runtime.md create mode 100644 docs/tutorials/data_pipeline.md create mode 100644 docs/tutorials/finetune.md create mode 100644 docs/tutorials/index.rst create mode 100644 docs/tutorials/init_cfg.md create mode 100644 docs/tutorials/onnx2tensorrt.md create mode 100644 docs/tutorials/pytorch2onnx.md create mode 100644 docs/useful_tools.md create mode 100644 docs_zh-CN/1_exist_data_model.md create mode 100644 docs_zh-CN/2_new_data_model.md create mode 100644 docs_zh-CN/3_exist_data_new_model.md create mode 100644 docs_zh-CN/Makefile create mode 100644 docs_zh-CN/_static/css/readthedocs.css create mode 100644 docs_zh-CN/_static/image/mmdet-logo.png create mode 100644 docs_zh-CN/api.rst create mode 100644 docs_zh-CN/compatibility.md create mode 100644 docs_zh-CN/conf.py create mode 100644 docs_zh-CN/conventions.md create mode 100644 docs_zh-CN/faq.md create mode 100644 docs_zh-CN/get_started.md create mode 100644 docs_zh-CN/index.rst create mode 100644 docs_zh-CN/make.bat create mode 100644 docs_zh-CN/model_zoo.md create mode 100644 docs_zh-CN/projects.md create mode 100644 docs_zh-CN/robustness_benchmarking.md create mode 100644 docs_zh-CN/stat.py create mode 100644 docs_zh-CN/switch_language.md create mode 100644 docs_zh-CN/tutorials/config.md create mode 100644 docs_zh-CN/tutorials/customize_dataset.md create mode 100644 docs_zh-CN/tutorials/customize_losses.md create mode 100644 docs_zh-CN/tutorials/customize_models.md create mode 100644 docs_zh-CN/tutorials/customize_runtime.md create mode 100644 docs_zh-CN/tutorials/data_pipeline.md create mode 100644 docs_zh-CN/tutorials/finetune.md create mode 100644 docs_zh-CN/tutorials/index.rst create mode 100644 docs_zh-CN/tutorials/onnx2tensorrt.md create mode 100644 docs_zh-CN/tutorials/pytorch2onnx.md create mode 100644 docs_zh-CN/useful_tools.md create mode 100644 mmdet/__init__.py create mode 100644 mmdet/apis/__init__.py create mode 100644 mmdet/apis/inference.py create mode 100644 mmdet/apis/test.py create mode 100644 mmdet/apis/train.py create mode 100644 mmdet/core/__init__.py create mode 100644 mmdet/core/anchor/__init__.py create mode 100644 mmdet/core/anchor/anchor_generator.py create mode 100644 mmdet/core/anchor/builder.py create mode 100644 mmdet/core/anchor/point_generator.py create mode 100644 mmdet/core/anchor/utils.py create mode 100644 mmdet/core/bbox/__init__.py create mode 100644 mmdet/core/bbox/assigners/__init__.py create mode 100644 mmdet/core/bbox/assigners/approx_max_iou_assigner.py create mode 100644 mmdet/core/bbox/assigners/assign_result.py create mode 100644 mmdet/core/bbox/assigners/atss_assigner.py create mode 100644 mmdet/core/bbox/assigners/base_assigner.py create mode 100644 mmdet/core/bbox/assigners/center_region_assigner.py create mode 100644 mmdet/core/bbox/assigners/grid_assigner.py create mode 100644 mmdet/core/bbox/assigners/hungarian_assigner.py create mode 100644 mmdet/core/bbox/assigners/max_iou_assigner.py create mode 100644 mmdet/core/bbox/assigners/point_assigner.py create mode 100644 mmdet/core/bbox/assigners/region_assigner.py create mode 100644 mmdet/core/bbox/assigners/sim_ota_assigner.py create mode 100644 mmdet/core/bbox/assigners/uniform_assigner.py create mode 100644 mmdet/core/bbox/builder.py create mode 100644 mmdet/core/bbox/coder/__init__.py create mode 100644 mmdet/core/bbox/coder/base_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/bucketing_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/delta_xywh_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/distance_point_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/legacy_delta_xywh_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/pseudo_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/tblr_bbox_coder.py create mode 100644 mmdet/core/bbox/coder/yolo_bbox_coder.py create mode 100644 mmdet/core/bbox/demodata.py create mode 100644 mmdet/core/bbox/iou_calculators/__init__.py create mode 100644 mmdet/core/bbox/iou_calculators/builder.py create mode 100644 mmdet/core/bbox/iou_calculators/iou2d_calculator.py create mode 100644 mmdet/core/bbox/match_costs/__init__.py create mode 100644 mmdet/core/bbox/match_costs/builder.py create mode 100644 mmdet/core/bbox/match_costs/match_cost.py create mode 100644 mmdet/core/bbox/samplers/__init__.py create mode 100644 mmdet/core/bbox/samplers/base_sampler.py create mode 100644 mmdet/core/bbox/samplers/combined_sampler.py create mode 100644 mmdet/core/bbox/samplers/instance_balanced_pos_sampler.py create mode 100644 mmdet/core/bbox/samplers/iou_balanced_neg_sampler.py create mode 100644 mmdet/core/bbox/samplers/ohem_sampler.py create mode 100644 mmdet/core/bbox/samplers/pseudo_sampler.py create mode 100644 mmdet/core/bbox/samplers/random_sampler.py create mode 100644 mmdet/core/bbox/samplers/sampling_result.py create mode 100644 mmdet/core/bbox/samplers/score_hlr_sampler.py create mode 100644 mmdet/core/bbox/transforms.py create mode 100644 mmdet/core/data_structures/__init__.py create mode 100644 mmdet/core/data_structures/general_data.py create mode 100644 mmdet/core/data_structures/instance_data.py create mode 100644 mmdet/core/evaluation/__init__.py create mode 100644 mmdet/core/evaluation/bbox_overlaps.py create mode 100644 mmdet/core/evaluation/class_names.py create mode 100644 mmdet/core/evaluation/eval_hooks.py create mode 100644 mmdet/core/evaluation/mean_ap.py create mode 100644 mmdet/core/evaluation/recall.py create mode 100644 mmdet/core/export/__init__.py create mode 100644 mmdet/core/export/model_wrappers.py create mode 100644 mmdet/core/export/onnx_helper.py create mode 100644 mmdet/core/export/pytorch2onnx.py create mode 100644 mmdet/core/hook/__init__.py create mode 100644 mmdet/core/hook/checkloss_hook.py create mode 100644 mmdet/core/hook/ema.py create mode 100644 mmdet/core/hook/pix2seq_lrupdater_hook.py create mode 100644 mmdet/core/hook/sync_norm_hook.py create mode 100644 mmdet/core/hook/sync_random_size_hook.py create mode 100644 mmdet/core/hook/yolox_lrupdater_hook.py create mode 100644 mmdet/core/hook/yolox_mode_switch_hook.py create mode 100644 mmdet/core/mask/__init__.py create mode 100644 mmdet/core/mask/mask_target.py create mode 100644 mmdet/core/mask/structures.py create mode 100644 mmdet/core/mask/utils.py create mode 100644 mmdet/core/post_processing/__init__.py create mode 100644 mmdet/core/post_processing/bbox_nms.py create mode 100644 mmdet/core/post_processing/matrix_nms.py create mode 100644 mmdet/core/post_processing/merge_augs.py create mode 100644 mmdet/core/utils/__init__.py create mode 100644 mmdet/core/utils/dist_utils.py create mode 100644 mmdet/core/utils/misc.py create mode 100644 mmdet/core/visualization/__init__.py create mode 100644 mmdet/core/visualization/image.py create mode 100644 mmdet/datasets/__init__.py create mode 100644 mmdet/datasets/api_wrappers/__init__.py create mode 100644 mmdet/datasets/api_wrappers/coco_api.py create mode 100644 mmdet/datasets/builder.py create mode 100644 mmdet/datasets/cityscapes.py create mode 100644 mmdet/datasets/coco.py create mode 100644 mmdet/datasets/coco_panoptic.py create mode 100644 mmdet/datasets/coco_pix2seq.py create mode 100644 mmdet/datasets/custom.py create mode 100644 mmdet/datasets/dataset_wrappers.py create mode 100644 mmdet/datasets/deepfashion.py create mode 100644 mmdet/datasets/lvis.py create mode 100644 mmdet/datasets/pipelines/__init__.py create mode 100644 mmdet/datasets/pipelines/auto_augment.py create mode 100644 mmdet/datasets/pipelines/compose.py create mode 100644 mmdet/datasets/pipelines/formating.py create mode 100644 mmdet/datasets/pipelines/instaboost.py create mode 100644 mmdet/datasets/pipelines/loading.py create mode 100644 mmdet/datasets/pipelines/test_time_aug.py create mode 100644 mmdet/datasets/pipelines/transforms.py create mode 100644 mmdet/datasets/samplers/__init__.py create mode 100644 mmdet/datasets/samplers/distributed_sampler.py create mode 100644 mmdet/datasets/samplers/group_sampler.py create mode 100644 mmdet/datasets/samplers/infinite_sampler.py create mode 100644 mmdet/datasets/utils.py create mode 100644 mmdet/datasets/voc.py create mode 100644 mmdet/datasets/wider_face.py create mode 100644 mmdet/datasets/xml_style.py create mode 100644 mmdet/models/__init__.py create mode 100644 mmdet/models/backbones/__init__.py create mode 100644 mmdet/models/backbones/csp_darknet.py create mode 100644 mmdet/models/backbones/darknet.py create mode 100644 mmdet/models/backbones/detectors_resnet.py create mode 100644 mmdet/models/backbones/detectors_resnext.py create mode 100644 mmdet/models/backbones/hourglass.py create mode 100644 mmdet/models/backbones/hrnet.py create mode 100644 mmdet/models/backbones/mobilenet_v2.py create mode 100644 mmdet/models/backbones/pvt.py create mode 100644 mmdet/models/backbones/regnet.py create mode 100644 mmdet/models/backbones/res2net.py create mode 100644 mmdet/models/backbones/resnest.py create mode 100644 mmdet/models/backbones/resnet.py create mode 100644 mmdet/models/backbones/resnext.py create mode 100644 mmdet/models/backbones/ssd_vgg.py create mode 100644 mmdet/models/backbones/swin.py create mode 100644 mmdet/models/backbones/trident_resnet.py create mode 100644 mmdet/models/builder.py create mode 100644 mmdet/models/dense_heads/__init__.py create mode 100644 mmdet/models/dense_heads/anchor_free_head.py create mode 100644 mmdet/models/dense_heads/anchor_head.py create mode 100644 mmdet/models/dense_heads/atss_head.py create mode 100644 mmdet/models/dense_heads/autoassign_head.py create mode 100644 mmdet/models/dense_heads/base_dense_head.py create mode 100644 mmdet/models/dense_heads/base_mask_head.py create mode 100644 mmdet/models/dense_heads/cascade_rpn_head.py create mode 100644 mmdet/models/dense_heads/centernet_head.py create mode 100644 mmdet/models/dense_heads/centripetal_head.py create mode 100644 mmdet/models/dense_heads/corner_head.py create mode 100644 mmdet/models/dense_heads/deformable_detr_head.py create mode 100644 mmdet/models/dense_heads/dense_test_mixins.py create mode 100644 mmdet/models/dense_heads/detr_head.py create mode 100644 mmdet/models/dense_heads/embedding_rpn_head.py create mode 100644 mmdet/models/dense_heads/fcos_head.py create mode 100644 mmdet/models/dense_heads/fovea_head.py create mode 100644 mmdet/models/dense_heads/free_anchor_retina_head.py create mode 100644 mmdet/models/dense_heads/fsaf_head.py create mode 100644 mmdet/models/dense_heads/ga_retina_head.py create mode 100644 mmdet/models/dense_heads/ga_rpn_head.py create mode 100644 mmdet/models/dense_heads/gfl_head.py create mode 100644 mmdet/models/dense_heads/guided_anchor_head.py create mode 100644 mmdet/models/dense_heads/ld_head.py create mode 100644 mmdet/models/dense_heads/nasfcos_head.py create mode 100644 mmdet/models/dense_heads/paa_head.py create mode 100644 mmdet/models/dense_heads/pisa_retinanet_head.py create mode 100644 mmdet/models/dense_heads/pisa_ssd_head.py create mode 100644 mmdet/models/dense_heads/pix2seq_head.py create mode 100644 mmdet/models/dense_heads/reppoints_head.py create mode 100644 mmdet/models/dense_heads/retina_head.py create mode 100644 mmdet/models/dense_heads/retina_sepbn_head.py create mode 100644 mmdet/models/dense_heads/rpn_head.py create mode 100644 mmdet/models/dense_heads/sabl_retina_head.py create mode 100644 mmdet/models/dense_heads/solo_head.py create mode 100644 mmdet/models/dense_heads/ssd_head.py create mode 100644 mmdet/models/dense_heads/vfnet_head.py create mode 100644 mmdet/models/dense_heads/yolact_head.py create mode 100644 mmdet/models/dense_heads/yolo_head.py create mode 100644 mmdet/models/dense_heads/yolof_head.py create mode 100644 mmdet/models/dense_heads/yolox_head.py create mode 100644 mmdet/models/detectors/__init__.py create mode 100644 mmdet/models/detectors/atss.py create mode 100644 mmdet/models/detectors/autoassign.py create mode 100644 mmdet/models/detectors/base.py create mode 100644 mmdet/models/detectors/cascade_rcnn.py create mode 100644 mmdet/models/detectors/centernet.py create mode 100644 mmdet/models/detectors/cornernet.py create mode 100644 mmdet/models/detectors/deformable_detr.py create mode 100644 mmdet/models/detectors/detr.py create mode 100644 mmdet/models/detectors/fast_rcnn.py create mode 100644 mmdet/models/detectors/faster_rcnn.py create mode 100644 mmdet/models/detectors/fcos.py create mode 100644 mmdet/models/detectors/fovea.py create mode 100644 mmdet/models/detectors/fsaf.py create mode 100644 mmdet/models/detectors/gfl.py create mode 100644 mmdet/models/detectors/grid_rcnn.py create mode 100644 mmdet/models/detectors/htc.py create mode 100644 mmdet/models/detectors/kd_one_stage.py create mode 100644 mmdet/models/detectors/mask_rcnn.py create mode 100644 mmdet/models/detectors/mask_scoring_rcnn.py create mode 100644 mmdet/models/detectors/nasfcos.py create mode 100644 mmdet/models/detectors/paa.py create mode 100644 mmdet/models/detectors/panoptic_fpn.py create mode 100644 mmdet/models/detectors/panoptic_two_stage_segmentor.py create mode 100644 mmdet/models/detectors/pix2seq.py create mode 100644 mmdet/models/detectors/point_rend.py create mode 100644 mmdet/models/detectors/queryinst.py create mode 100644 mmdet/models/detectors/reppoints_detector.py create mode 100644 mmdet/models/detectors/retinanet.py create mode 100644 mmdet/models/detectors/rpn.py create mode 100644 mmdet/models/detectors/scnet.py create mode 100644 mmdet/models/detectors/single_stage.py create mode 100644 mmdet/models/detectors/single_stage_instance_seg.py create mode 100644 mmdet/models/detectors/solo.py create mode 100644 mmdet/models/detectors/sparse_rcnn.py create mode 100644 mmdet/models/detectors/trident_faster_rcnn.py create mode 100644 mmdet/models/detectors/two_stage.py create mode 100644 mmdet/models/detectors/vfnet.py create mode 100644 mmdet/models/detectors/yolact.py create mode 100644 mmdet/models/detectors/yolo.py create mode 100644 mmdet/models/detectors/yolof.py create mode 100644 mmdet/models/detectors/yolox.py create mode 100644 mmdet/models/losses/__init__.py create mode 100644 mmdet/models/losses/accuracy.py create mode 100644 mmdet/models/losses/ae_loss.py create mode 100644 mmdet/models/losses/balanced_l1_loss.py create mode 100644 mmdet/models/losses/cross_entropy_loss.py create mode 100644 mmdet/models/losses/dice_loss.py create mode 100644 mmdet/models/losses/focal_loss.py create mode 100644 mmdet/models/losses/gaussian_focal_loss.py create mode 100644 mmdet/models/losses/gfocal_loss.py create mode 100644 mmdet/models/losses/ghm_loss.py create mode 100644 mmdet/models/losses/iou_loss.py create mode 100644 mmdet/models/losses/kd_loss.py create mode 100644 mmdet/models/losses/mse_loss.py create mode 100644 mmdet/models/losses/pisa_loss.py create mode 100644 mmdet/models/losses/seesaw_loss.py create mode 100644 mmdet/models/losses/smooth_l1_loss.py create mode 100644 mmdet/models/losses/utils.py create mode 100644 mmdet/models/losses/varifocal_loss.py create mode 100644 mmdet/models/necks/__init__.py create mode 100644 mmdet/models/necks/bfp.py create mode 100644 mmdet/models/necks/channel_mapper.py create mode 100644 mmdet/models/necks/ct_resnet_neck.py create mode 100644 mmdet/models/necks/dilated_encoder.py create mode 100644 mmdet/models/necks/fpg.py create mode 100644 mmdet/models/necks/fpn.py create mode 100644 mmdet/models/necks/fpn_carafe.py create mode 100644 mmdet/models/necks/hrfpn.py create mode 100644 mmdet/models/necks/nas_fpn.py create mode 100644 mmdet/models/necks/nasfcos_fpn.py create mode 100644 mmdet/models/necks/pafpn.py create mode 100644 mmdet/models/necks/rfp.py create mode 100644 mmdet/models/necks/ssd_neck.py create mode 100644 mmdet/models/necks/yolo_neck.py create mode 100644 mmdet/models/necks/yolox_pafpn.py create mode 100644 mmdet/models/plugins/__init__.py create mode 100644 mmdet/models/plugins/dropblock.py create mode 100644 mmdet/models/roi_heads/__init__.py create mode 100644 mmdet/models/roi_heads/base_roi_head.py create mode 100644 mmdet/models/roi_heads/bbox_heads/__init__.py create mode 100644 mmdet/models/roi_heads/bbox_heads/bbox_head.py create mode 100644 mmdet/models/roi_heads/bbox_heads/convfc_bbox_head.py create mode 100644 mmdet/models/roi_heads/bbox_heads/dii_head.py create mode 100644 mmdet/models/roi_heads/bbox_heads/double_bbox_head.py create mode 100644 mmdet/models/roi_heads/bbox_heads/sabl_head.py create mode 100644 mmdet/models/roi_heads/bbox_heads/scnet_bbox_head.py create mode 100644 mmdet/models/roi_heads/cascade_roi_head.py create mode 100644 mmdet/models/roi_heads/double_roi_head.py create mode 100644 mmdet/models/roi_heads/dynamic_roi_head.py create mode 100644 mmdet/models/roi_heads/grid_roi_head.py create mode 100644 mmdet/models/roi_heads/htc_roi_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/__init__.py create mode 100644 mmdet/models/roi_heads/mask_heads/coarse_mask_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/dynamic_mask_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/fcn_mask_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/feature_relay_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/fused_semantic_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/global_context_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/grid_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/htc_mask_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/mask_point_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/maskiou_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/scnet_mask_head.py create mode 100644 mmdet/models/roi_heads/mask_heads/scnet_semantic_head.py create mode 100644 mmdet/models/roi_heads/mask_scoring_roi_head.py create mode 100644 mmdet/models/roi_heads/pisa_roi_head.py create mode 100644 mmdet/models/roi_heads/point_rend_roi_head.py create mode 100644 mmdet/models/roi_heads/roi_extractors/__init__.py create mode 100644 mmdet/models/roi_heads/roi_extractors/base_roi_extractor.py create mode 100644 mmdet/models/roi_heads/roi_extractors/generic_roi_extractor.py create mode 100644 mmdet/models/roi_heads/roi_extractors/single_level_roi_extractor.py create mode 100644 mmdet/models/roi_heads/scnet_roi_head.py create mode 100644 mmdet/models/roi_heads/shared_heads/__init__.py create mode 100644 mmdet/models/roi_heads/shared_heads/res_layer.py create mode 100644 mmdet/models/roi_heads/sparse_roi_head.py create mode 100644 mmdet/models/roi_heads/standard_roi_head.py create mode 100644 mmdet/models/roi_heads/test_mixins.py create mode 100644 mmdet/models/roi_heads/trident_roi_head.py create mode 100644 mmdet/models/seg_heads/__init__.py create mode 100644 mmdet/models/seg_heads/base_semantic_head.py create mode 100644 mmdet/models/seg_heads/panoptic_fpn_head.py create mode 100644 mmdet/models/seg_heads/panoptic_fusion_heads/__init__.py create mode 100644 mmdet/models/seg_heads/panoptic_fusion_heads/base_panoptic_fusion_head.py create mode 100644 mmdet/models/seg_heads/panoptic_fusion_heads/heuristic_fusion_head.py create mode 100644 mmdet/models/utils/__init__.py create mode 100644 mmdet/models/utils/brick_wrappers.py create mode 100644 mmdet/models/utils/builder.py create mode 100644 mmdet/models/utils/ckpt_convert.py create mode 100644 mmdet/models/utils/conv_upsample.py create mode 100644 mmdet/models/utils/csp_layer.py create mode 100644 mmdet/models/utils/gaussian_target.py create mode 100644 mmdet/models/utils/inverted_residual.py create mode 100644 mmdet/models/utils/make_divisible.py create mode 100644 mmdet/models/utils/misc.py create mode 100644 mmdet/models/utils/normed_predictor.py create mode 100644 mmdet/models/utils/positional_encoding.py create mode 100644 mmdet/models/utils/res_layer.py create mode 100644 mmdet/models/utils/se_layer.py create mode 100644 mmdet/models/utils/transformer.py create mode 100644 mmdet/models/utils/transformer_old.py create mode 100644 mmdet/utils/__init__.py create mode 100644 mmdet/utils/collect_env.py create mode 100644 mmdet/utils/contextmanagers.py create mode 100644 mmdet/utils/logger.py create mode 100644 mmdet/utils/profiling.py create mode 100644 mmdet/utils/util_mixins.py create mode 100644 mmdet/utils/util_random.py create mode 100644 mmdet/version.py create mode 100644 model-index.yml create mode 100644 pytest.ini create mode 100644 requirements.txt create mode 100644 requirements/build.txt create mode 100644 requirements/docs.txt create mode 100644 requirements/mminstall.txt create mode 100644 requirements/optional.txt create mode 100644 requirements/readthedocs.txt create mode 100644 requirements/runtime.txt create mode 100644 requirements/tests.txt create mode 100644 resources/000000212559.jpg create mode 100644 resources/000000255664.jpg create mode 100644 resources/000000289393.jpg create mode 100644 resources/007114.jpg create mode 100644 resources/007351.jpg create mode 100644 resources/008322.jpg create mode 100644 resources/coco_test_12510.jpg create mode 100644 resources/corruptions_sev_3.png create mode 100644 resources/data_pipeline.png create mode 100644 resources/loss_curve.png create mode 100644 resources/mmdet-logo.png create mode 100644 resources/qq_group_qrcode.jpg create mode 100644 resources/vqvae-framework.png create mode 100644 resources/zhihu_qrcode.jpg create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 tests/test_data/test_datasets/test_coco_dataset.py create mode 100644 tests/test_data/test_datasets/test_common.py create mode 100644 tests/test_data/test_datasets/test_custom_dataset.py create mode 100644 tests/test_data/test_datasets/test_dataset_wrapper.py create mode 100644 tests/test_data/test_datasets/test_panoptic_dataset.py create mode 100644 tests/test_data/test_datasets/test_xml_dataset.py create mode 100644 tests/test_data/test_pipelines/test_formatting.py create mode 100644 tests/test_data/test_pipelines/test_loading.py create mode 100644 tests/test_data/test_pipelines/test_sampler.py create mode 100644 tests/test_data/test_pipelines/test_transform/__init__.py create mode 100644 tests/test_data/test_pipelines/test_transform/test_img_augment.py create mode 100644 tests/test_data/test_pipelines/test_transform/test_models_aug_test.py create mode 100644 tests/test_data/test_pipelines/test_transform/test_rotate.py create mode 100644 tests/test_data/test_pipelines/test_transform/test_shear.py create mode 100644 tests/test_data/test_pipelines/test_transform/test_transform.py create mode 100644 tests/test_data/test_pipelines/test_transform/test_translate.py create mode 100644 tests/test_data/test_pipelines/test_transform/utils.py create mode 100644 tests/test_data/test_utils.py create mode 100644 tests/test_downstream/test_mmtrack.py create mode 100644 tests/test_metrics/test_box_overlap.py create mode 100644 tests/test_metrics/test_losses.py create mode 100644 tests/test_metrics/test_mean_ap.py create mode 100644 tests/test_metrics/test_recall.py create mode 100644 tests/test_models/test_backbones/__init__.py create mode 100644 tests/test_models/test_backbones/test_csp_darknet.py create mode 100644 tests/test_models/test_backbones/test_detectors_resnet.py create mode 100644 tests/test_models/test_backbones/test_hourglass.py create mode 100644 tests/test_models/test_backbones/test_hrnet.py create mode 100644 tests/test_models/test_backbones/test_mobilenet_v2.py create mode 100644 tests/test_models/test_backbones/test_pvt.py create mode 100644 tests/test_models/test_backbones/test_regnet.py create mode 100644 tests/test_models/test_backbones/test_renext.py create mode 100644 tests/test_models/test_backbones/test_res2net.py create mode 100644 tests/test_models/test_backbones/test_resnest.py create mode 100644 tests/test_models/test_backbones/test_resnet.py create mode 100644 tests/test_models/test_backbones/test_swin.py create mode 100644 tests/test_models/test_backbones/test_trident_resnet.py create mode 100644 tests/test_models/test_backbones/utils.py create mode 100644 tests/test_models/test_dense_heads/test_anchor_head.py create mode 100644 tests/test_models/test_dense_heads/test_atss_head.py create mode 100644 tests/test_models/test_dense_heads/test_autoassign_head.py create mode 100644 tests/test_models/test_dense_heads/test_centernet_head.py create mode 100644 tests/test_models/test_dense_heads/test_corner_head.py create mode 100644 tests/test_models/test_dense_heads/test_dense_heads_attr.py create mode 100644 tests/test_models/test_dense_heads/test_detr_head.py create mode 100644 tests/test_models/test_dense_heads/test_fcos_head.py create mode 100644 tests/test_models/test_dense_heads/test_fsaf_head.py create mode 100644 tests/test_models/test_dense_heads/test_ga_anchor_head.py create mode 100644 tests/test_models/test_dense_heads/test_gfl_head.py create mode 100644 tests/test_models/test_dense_heads/test_ld_head.py create mode 100644 tests/test_models/test_dense_heads/test_paa_head.py create mode 100644 tests/test_models/test_dense_heads/test_pisa_head.py create mode 100644 tests/test_models/test_dense_heads/test_sabl_retina_head.py create mode 100644 tests/test_models/test_dense_heads/test_solo_head.py create mode 100644 tests/test_models/test_dense_heads/test_vfnet_head.py create mode 100644 tests/test_models/test_dense_heads/test_yolact_head.py create mode 100644 tests/test_models/test_dense_heads/test_yolof_head.py create mode 100644 tests/test_models/test_dense_heads/test_yolox_head.py create mode 100644 tests/test_models/test_forward.py create mode 100644 tests/test_models/test_loss.py create mode 100644 tests/test_models/test_loss_compatibility.py create mode 100644 tests/test_models/test_necks.py create mode 100644 tests/test_models/test_plugins.py create mode 100644 tests/test_models/test_roi_heads/__init__.py create mode 100644 tests/test_models/test_roi_heads/test_bbox_head.py create mode 100644 tests/test_models/test_roi_heads/test_mask_head.py create mode 100644 tests/test_models/test_roi_heads/test_roi_extractor.py create mode 100644 tests/test_models/test_roi_heads/test_sabl_bbox_head.py create mode 100644 tests/test_models/test_roi_heads/utils.py create mode 100644 tests/test_models/test_utils/test_brick_wrappers.py create mode 100644 tests/test_models/test_utils/test_conv_upsample.py create mode 100644 tests/test_models/test_utils/test_inverted_residual.py create mode 100644 tests/test_models/test_utils/test_model_misc.py create mode 100644 tests/test_models/test_utils/test_position_encoding.py create mode 100644 tests/test_models/test_utils/test_se_layer.py create mode 100644 tests/test_models/test_utils/test_transformer.py create mode 100644 tests/test_onnx/__init__.py create mode 100644 tests/test_onnx/test_head.py create mode 100644 tests/test_onnx/test_neck.py create mode 100644 tests/test_onnx/utils.py create mode 100644 tests/test_runtime/async_benchmark.py create mode 100644 tests/test_runtime/test_async.py create mode 100644 tests/test_runtime/test_config.py create mode 100644 tests/test_runtime/test_eval_hook.py create mode 100644 tests/test_runtime/test_fp16.py create mode 100644 tests/test_utils/test_anchor.py create mode 100644 tests/test_utils/test_assigner.py create mode 100644 tests/test_utils/test_coder.py create mode 100644 tests/test_utils/test_general_data.py create mode 100644 tests/test_utils/test_hook.py create mode 100644 tests/test_utils/test_masks.py create mode 100644 tests/test_utils/test_misc.py create mode 100644 tests/test_utils/test_nms.py create mode 100644 tests/test_utils/test_version.py create mode 100644 tests/test_utils/test_visualization.py create mode 100644 tools/analysis_tools/analyze_logs.py create mode 100644 tools/analysis_tools/analyze_results.py create mode 100644 tools/analysis_tools/benchmark.py create mode 100644 tools/analysis_tools/coco_error_analysis.py create mode 100644 tools/analysis_tools/confusion_matrix.py create mode 100644 tools/analysis_tools/eval_metric.py create mode 100644 tools/analysis_tools/get_flops.py create mode 100644 tools/analysis_tools/optimize_anchors.py create mode 100644 tools/analysis_tools/robustness_eval.py create mode 100644 tools/analysis_tools/test_robustness.py create mode 100644 tools/dataset_converters/cityscapes.py create mode 100644 tools/dataset_converters/images2coco.py create mode 100644 tools/dataset_converters/pascal_voc.py create mode 100644 tools/deployment/mmdet2torchserve.py create mode 100644 tools/deployment/mmdet_handler.py create mode 100644 tools/deployment/onnx2tensorrt.py create mode 100644 tools/deployment/pytorch2onnx.py create mode 100644 tools/deployment/test.py create mode 100644 tools/deployment/test_torchserver.py create mode 100644 tools/dist_test.sh create mode 100644 tools/dist_train.sh create mode 100644 tools/misc/browse_dataset.py create mode 100644 tools/misc/print_config.py create mode 100644 tools/model_converters/detectron2pytorch.py create mode 100644 tools/model_converters/publish_model.py create mode 100644 tools/model_converters/regnet2mmdet.py create mode 100644 tools/model_converters/selfsup2mmdet.py create mode 100644 tools/model_converters/upgrade_model_version.py create mode 100644 tools/model_converters/upgrade_ssd_version.py create mode 100644 tools/slurm_test.sh create mode 100644 tools/slurm_train.sh create mode 100644 tools/test.py create mode 100644 tools/train.py diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..aac9313 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,8 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: + - name: "MMDetection Contributors" +title: "OpenMMLab Detection Toolbox and Benchmark" +date-released: 2018-08-22 +url: "https://github.com/open-mmlab/mmdetection" +license: Apache-2.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1bfc23e --- /dev/null +++ b/LICENSE @@ -0,0 +1,203 @@ +Copyright 2018-2023 OpenMMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2023 OpenMMLab. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..6300b22 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +include requirements/*.txt +include mmdet/VERSION +include mmdet/.mim/model-index.yml +include mmdet/.mim/demo/*/* +recursive-include mmdet/.mim/configs *.py *.yml +recursive-include mmdet/.mim/tools *.sh *.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..78044b0 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +## Introduction + +This is an unofficial replication of "Pix2seq: A Language Modeling Framework for Object Detection" with pretrained model on mmdetection. + +## License + +This project is released under the [Apache 2.0 license](LICENSE). + +## Installation + +Please refer to [get_started.md](docs/get_started.md) for installation. + +## Train & Evaluation + +Train by running (about 10 days with 8*V100 32GB) +```bash +python -m torch.distributed.launch --nproc_per_node=8 --master_port=5003 \ + tools/train.py configs/pix2seq/pix2seq_r50_8x4_50e_coco.py --work-dir pix2seq-output --gpus 8 --launcher pytorch +``` + +or + +Download [pretrained pix2seq weights](https://drive.google.com/file/d/1Ku8ZORiLtMs66uleS3aXId7pxlJrTK9d/view?usp=sharing). + +Evaluate with single gpu: +```bash +python tools/test.py configs/pix2seq/pix2seq_r50_8x4_300_coco.py \ + weights/checkpoints.pth --work-dir pix2seq-output --eval bbox --show-dir pix2seq-vis +``` + +Evaluate with 8 gpus: +```bash +python -m torch.distributed.launch --nproc_per_node=8 --master_port=5003 \ + tools/test.py configs/pix2seq/pix2seq_r50_8x4_300_coco.py weights/checkpoints.pth \ + --work-dir pix2seq-output --eval bbox --launcher pytorch +``` + +| Method | backbone | Epoch | Batch Size | AP | AP50 | AP75 | +| :-----: | :------: | :----:| :---------:| :---:| :---: | :---: | +| Ours | R50 | 300 | 32 | 36.4 | 52.8 | 38.5 | +| Paper | R50 | 300 | 128 | 43.0 | 61.0 | 45.6 | + + +## Visualization + +![](https://github.com/Sharpiless/mmdet-Pix2Seq/blob/main/resources/007114.jpg) + +![](https://github.com/Sharpiless/mmdet-Pix2Seq/blob/main/resources/007351.jpg) + +![](https://github.com/Sharpiless/mmdet-Pix2Seq/blob/main/resources/008322.jpg) + +![](https://github.com/Sharpiless/mmdet-Pix2Seq/blob/main/resources/000000289393.jpg) + +![](https://github.com/Sharpiless/mmdet-Pix2Seq/blob/main/resources/000000212559.jpg) + +![](https://github.com/Sharpiless/mmdet-Pix2Seq/blob/main/resources/000000255664.jpg) + +## TO-DO + +- [x] random shuffle targets +- [x] training from scratch +- [x] drop class token +- [x] stochastic depth +- [x] large scale jittering +- [ ] support for custom dataset +- [x] two independent augmentations for each image +- [x] FrozenBatchNorm2d in backbones +- [x] auto-argument +- [x] nucleus sampling + +## Acknowledgement + +[https://github.com/gaopengcuhk/Pretrained-Pix2Seq](https://github.com/gaopengcuhk/Pretrained-Pix2Seq) + +[https://github.com/open-mmlab/mmdetection](https://github.com/open-mmlab/mmdetection) diff --git a/README_zh-CN.md b/README_zh-CN.md new file mode 100644 index 0000000..043e812 --- /dev/null +++ b/README_zh-CN.md @@ -0,0 +1,14 @@ +$$ +\begin{array}{l} +P(z_{n} \geq z_{n^{\prime}} ; \forall n^{\prime} \neq n \mid\{\pi_{n^{\prime}}\}_{n^{\prime}=1}^{N})\\ +=\int \prod_{n^{\prime} \neq n} e^{-e^{-(z_{n}-\pi_{n^{\prime}})}} \cdot e^{-(z_{n}-\pi_{n})-e^{-(z_{n}-\pi_{n})}} d z_{n}\\ +=\int e^{-\sum_{n^{\prime} \neq n} e^{-(z_{n}-\pi_{n})}-(z_{n}-\pi_{n})-e^{-(z_{n}-\pi_{n})}} d z_{n}\\ +=\int e^{-\sum_{n=1}^{N} e^{-(z_{n}-\pi_{n^{\prime}})}-(z_{n}-\pi_{n})} d z_{n}\\ +=\int e^{-(\sum_{n=1}^{N} e^{\pi_{n^{\prime}}}) e^{-z_{n}}-z_{n}+\pi_{n}} d z_{n}\\ +=\int e^{-e^{-z_{n}+\ln (\sum_{n=1}^{N}} e^{\pi^{\pi} n})_{-z_{n}+\pi_{n}} d z_{n}}\\ +=\int e^{-e^{-(z_{n}-\ln (\sum_{n=1}^{N}} e^{\pi_{n^{\prime}}}))}(z_{n}-\ln (\sum_{n^{\prime}=1}^{N} e^{\pi_{n^{\prime}}}))-\ln (\sum_{n^{\prime}=1}^{N} e^{\pi^{\prime}} n^{\prime})+\pi_{n} d z_{n}\\ +=e^{-\ln (\sum_{n^{\prime}}^{N} e^{e} e^{\pi_{\prime}})+\pi_{n}} \int e^{-e^{-(z_{n}-\ln (\sum_{n}^{N}=1} e^{\pi_{n^{\prime}}}))}(z_{n}-\ln (\sum_{n^{\prime}=1}^{N} e^{\pi_{n^{\prime}})} d z_{n}\\ +=\frac{e^{\pi_{n}}}{\sum_{n^{\prime}=1}^{N} e^{\pi_{n^{\prime}}}} \int e^{-e^{-(z_{n}-\ln (\sum_{n}^{N}=1} e^{\pi^{\prime}}{ }_{n}^{\prime}))}(z_{n}-\ln (\sum_{n^{\prime}=1}^{N} e^{.\pi_{n^{\prime}})}) d z_{n}\\ +=\frac{e^{\pi_{n}}}{\sum_{n=1}^{N} e^{\pi_{n^{\prime}}}} \int e^{-(z_{n}-\ln (\sum_{n=1}^{N} e^{\pi_{n^{\prime}}}))-e^{-(z_{n}-\ln (\sum_{n}^{N}=1} e^{\pi_{n^{\prime}}})} d z_{n} +\end{array} +$$ \ No newline at end of file diff --git a/configs/_base_/datasets/cityscapes_detection.py b/configs/_base_/datasets/cityscapes_detection.py new file mode 100644 index 0000000..e341b59 --- /dev/null +++ b/configs/_base_/datasets/cityscapes_detection.py @@ -0,0 +1,56 @@ +# dataset settings +dataset_type = 'CityscapesDataset' +data_root = 'data/cityscapes/' +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=[(2048, 800), (2048, 1024)], keep_ratio=True), + 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=(2048, 1024), + 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=1, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=8, + dataset=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/instancesonly_filtered_gtFine_train.json', + img_prefix=data_root + 'leftImg8bit/train/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/instancesonly_filtered_gtFine_val.json', + img_prefix=data_root + 'leftImg8bit/val/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/instancesonly_filtered_gtFine_test.json', + img_prefix=data_root + 'leftImg8bit/test/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric='bbox') diff --git a/configs/_base_/datasets/cityscapes_instance.py b/configs/_base_/datasets/cityscapes_instance.py new file mode 100644 index 0000000..4e3c34e --- /dev/null +++ b/configs/_base_/datasets/cityscapes_instance.py @@ -0,0 +1,56 @@ +# dataset settings +dataset_type = 'CityscapesDataset' +data_root = 'data/cityscapes/' +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, with_mask=True), + dict( + type='Resize', img_scale=[(2048, 800), (2048, 1024)], keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(2048, 1024), + 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=1, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=8, + dataset=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/instancesonly_filtered_gtFine_train.json', + img_prefix=data_root + 'leftImg8bit/train/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/instancesonly_filtered_gtFine_val.json', + img_prefix=data_root + 'leftImg8bit/val/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/instancesonly_filtered_gtFine_test.json', + img_prefix=data_root + 'leftImg8bit/test/', + pipeline=test_pipeline)) +evaluation = dict(metric=['bbox', 'segm']) diff --git a/configs/_base_/datasets/coco_detection.py b/configs/_base_/datasets/coco_detection.py new file mode 100644 index 0000000..149f590 --- /dev/null +++ b/configs/_base_/datasets/coco_detection.py @@ -0,0 +1,49 @@ +# 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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric='bbox') diff --git a/configs/_base_/datasets/coco_detection_pix2seq.py b/configs/_base_/datasets/coco_detection_pix2seq.py new file mode 100644 index 0000000..32035d4 --- /dev/null +++ b/configs/_base_/datasets/coco_detection_pix2seq.py @@ -0,0 +1,68 @@ +# dataset settings +dataset_type = 'Pix2seqCocoDataset' +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) +train_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(0.3, 2.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 1333), + flip=False, + transforms=[ + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(1.0, 1.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +data = dict( + samples_per_gpu=4, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline) +) + diff --git a/configs/_base_/datasets/coco_detection_vqvae.py b/configs/_base_/datasets/coco_detection_vqvae.py new file mode 100644 index 0000000..33bfa84 --- /dev/null +++ b/configs/_base_/datasets/coco_detection_vqvae.py @@ -0,0 +1,69 @@ +# dataset settings +dataset_type = 'VQVAECocoDataset' +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) +train_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(0.3, 2.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 1333), + flip=False, + transforms=[ + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(1.0, 1.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +data = dict( + samples_per_gpu=4, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline) +) + diff --git a/configs/_base_/datasets/coco_instance.py b/configs/_base_/datasets/coco_instance.py new file mode 100644 index 0000000..9901a85 --- /dev/null +++ b/configs/_base_/datasets/coco_instance.py @@ -0,0 +1,49 @@ +# 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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(metric=['bbox', 'segm']) diff --git a/configs/_base_/datasets/coco_instance_semantic.py b/configs/_base_/datasets/coco_instance_semantic.py new file mode 100644 index 0000000..6c8bf07 --- /dev/null +++ b/configs/_base_/datasets/coco_instance_semantic.py @@ -0,0 +1,54 @@ +# 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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', with_bbox=True, with_mask=True, with_seg=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='SegRescale', scale_factor=1 / 8), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks', 'gt_semantic_seg']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + 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=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + seg_prefix=data_root + 'stuffthingmaps/train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(metric=['bbox', 'segm']) diff --git a/configs/_base_/datasets/coco_panoptic.py b/configs/_base_/datasets/coco_panoptic.py new file mode 100644 index 0000000..dbade7c --- /dev/null +++ b/configs/_base_/datasets/coco_panoptic.py @@ -0,0 +1,59 @@ +# dataset settings +dataset_type = 'CocoPanopticDataset' +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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadPanopticAnnotations', + with_bbox=True, + with_mask=True, + with_seg=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='SegRescale', scale_factor=1 / 4), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks', 'gt_semantic_seg']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/panoptic_train2017.json', + img_prefix=data_root + 'train2017/', + seg_prefix=data_root + 'annotations/panoptic_train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/panoptic_val2017.json', + img_prefix=data_root + 'val2017/', + seg_prefix=data_root + 'annotations/panoptic_val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/panoptic_val2017.json', + img_prefix=data_root + 'val2017/', + seg_prefix=data_root + 'annotations/panoptic_val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric=['PQ']) diff --git a/configs/_base_/datasets/deepfashion.py b/configs/_base_/datasets/deepfashion.py new file mode 100644 index 0000000..308b4b2 --- /dev/null +++ b/configs/_base_/datasets/deepfashion.py @@ -0,0 +1,53 @@ +# dataset settings +dataset_type = 'DeepFashionDataset' +data_root = 'data/DeepFashion/In-shop/' +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, with_mask=True), + dict(type='Resize', img_scale=(750, 1101), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(750, 1101), + 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( + imgs_per_gpu=2, + workers_per_gpu=1, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/DeepFashion_segmentation_query.json', + img_prefix=data_root + 'Img/', + pipeline=train_pipeline, + data_root=data_root), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/DeepFashion_segmentation_query.json', + img_prefix=data_root + 'Img/', + pipeline=test_pipeline, + data_root=data_root), + test=dict( + type=dataset_type, + ann_file=data_root + + 'annotations/DeepFashion_segmentation_gallery.json', + img_prefix=data_root + 'Img/', + pipeline=test_pipeline, + data_root=data_root)) +evaluation = dict(interval=5, metric=['bbox', 'segm']) diff --git a/configs/_base_/datasets/lvis_v0.5_instance.py b/configs/_base_/datasets/lvis_v0.5_instance.py new file mode 100644 index 0000000..207e005 --- /dev/null +++ b/configs/_base_/datasets/lvis_v0.5_instance.py @@ -0,0 +1,24 @@ +# dataset settings +_base_ = 'coco_instance.py' +dataset_type = 'LVISV05Dataset' +data_root = 'data/lvis_v0.5/' +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + _delete_=True, + type='ClassBalancedDataset', + oversample_thr=1e-3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/lvis_v0.5_train.json', + img_prefix=data_root + 'train2017/')), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/lvis_v0.5_val.json', + img_prefix=data_root + 'val2017/'), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/lvis_v0.5_val.json', + img_prefix=data_root + 'val2017/')) +evaluation = dict(metric=['bbox', 'segm']) diff --git a/configs/_base_/datasets/lvis_v1_instance.py b/configs/_base_/datasets/lvis_v1_instance.py new file mode 100644 index 0000000..be791ed --- /dev/null +++ b/configs/_base_/datasets/lvis_v1_instance.py @@ -0,0 +1,24 @@ +# dataset settings +_base_ = 'coco_instance.py' +dataset_type = 'LVISV1Dataset' +data_root = 'data/lvis_v1/' +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + _delete_=True, + type='ClassBalancedDataset', + oversample_thr=1e-3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/lvis_v1_train.json', + img_prefix=data_root)), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/lvis_v1_val.json', + img_prefix=data_root), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/lvis_v1_val.json', + img_prefix=data_root)) +evaluation = dict(metric=['bbox', 'segm']) diff --git a/configs/_base_/datasets/voc0712.py b/configs/_base_/datasets/voc0712.py new file mode 100644 index 0000000..ae09acd --- /dev/null +++ b/configs/_base_/datasets/voc0712.py @@ -0,0 +1,55 @@ +# dataset settings +dataset_type = 'VOCDataset' +data_root = 'data/VOCdevkit/' +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), + 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), + 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=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=[ + data_root + 'VOC2007/ImageSets/Main/trainval.txt', + data_root + 'VOC2012/ImageSets/Main/trainval.txt' + ], + 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') diff --git a/configs/_base_/datasets/voc0712_pix2seq.py b/configs/_base_/datasets/voc0712_pix2seq.py new file mode 100644 index 0000000..264ec14 --- /dev/null +++ b/configs/_base_/datasets/voc0712_pix2seq.py @@ -0,0 +1,73 @@ +# dataset settings +dataset_type = 'VOCDataset' +data_root = 'data/VOCdevkit/' +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', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(0.3, 2.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 1333), + flip=False, + transforms=[ + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(1.0, 1.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=[ + data_root + 'VOC2007/ImageSets/Main/trainval.txt', + data_root + 'VOC2012/ImageSets/Main/trainval.txt' + ], + 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') diff --git a/configs/_base_/datasets/wider_face.py b/configs/_base_/datasets/wider_face.py new file mode 100644 index 0000000..d1d649b --- /dev/null +++ b/configs/_base_/datasets/wider_face.py @@ -0,0 +1,63 @@ +# dataset settings +dataset_type = 'WIDERFaceDataset' +data_root = 'data/WIDERFace/' +img_norm_cfg = dict(mean=[123.675, 116.28, 103.53], std=[1, 1, 1], to_rgb=True) +train_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='Expand', + mean=img_norm_cfg['mean'], + to_rgb=img_norm_cfg['to_rgb'], + ratio_range=(1, 4)), + dict( + type='MinIoURandomCrop', + min_ious=(0.1, 0.3, 0.5, 0.7, 0.9), + min_crop_size=0.3), + dict(type='Resize', img_scale=(300, 300), keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(300, 300), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=60, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=2, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'train.txt', + img_prefix=data_root + 'WIDER_train/', + min_size=17, + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + 'val.txt', + img_prefix=data_root + 'WIDER_val/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'val.txt', + img_prefix=data_root + 'WIDER_val/', + pipeline=test_pipeline)) diff --git a/configs/_base_/default_runtime.py b/configs/_base_/default_runtime.py new file mode 100644 index 0000000..55097c5 --- /dev/null +++ b/configs/_base_/default_runtime.py @@ -0,0 +1,16 @@ +checkpoint_config = dict(interval=1) +# yapf:disable +log_config = dict( + interval=50, + hooks=[ + dict(type='TextLoggerHook'), + # dict(type='TensorboardLoggerHook') + ]) +# yapf:enable +custom_hooks = [dict(type='NumClassCheckHook')] + +dist_params = dict(backend='nccl') +log_level = 'INFO' +load_from = None +resume_from = None +workflow = [('train', 1)] diff --git a/configs/_base_/models/cascade_mask_rcnn_r50_fpn.py b/configs/_base_/models/cascade_mask_rcnn_r50_fpn.py new file mode 100644 index 0000000..2902cca --- /dev/null +++ b/configs/_base_/models/cascade_mask_rcnn_r50_fpn.py @@ -0,0 +1,196 @@ +# model settings +model = dict( + type='CascadeRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + type='CascadeRoIHead', + num_stages=3, + stage_loss_weights=[1, 0.5, 0.25], + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=[ + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, + loss_weight=1.0)), + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.05, 0.05, 0.1, 0.1]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, + loss_weight=1.0)), + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.033, 0.033, 0.067, 0.067]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)) + ], + mask_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + mask_head=dict( + type='FCNMaskHead', + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=[ + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.6, + neg_iou_thr=0.6, + min_pos_iou=0.6, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.7, + min_pos_iou=0.7, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False) + ]), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100, + mask_thr_binary=0.5))) diff --git a/configs/_base_/models/cascade_rcnn_r50_fpn.py b/configs/_base_/models/cascade_rcnn_r50_fpn.py new file mode 100644 index 0000000..42f74ae --- /dev/null +++ b/configs/_base_/models/cascade_rcnn_r50_fpn.py @@ -0,0 +1,179 @@ +# model settings +model = dict( + type='CascadeRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + type='CascadeRoIHead', + num_stages=3, + stage_loss_weights=[1, 0.5, 0.25], + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=[ + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, + loss_weight=1.0)), + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.05, 0.05, 0.1, 0.1]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, + loss_weight=1.0)), + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.033, 0.033, 0.067, 0.067]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)) + ]), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=[ + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.6, + neg_iou_thr=0.6, + min_pos_iou=0.6, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.7, + min_pos_iou=0.7, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False) + ]), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100))) diff --git a/configs/_base_/models/fast_rcnn_r50_fpn.py b/configs/_base_/models/fast_rcnn_r50_fpn.py new file mode 100644 index 0000000..9982fe0 --- /dev/null +++ b/configs/_base_/models/fast_rcnn_r50_fpn.py @@ -0,0 +1,62 @@ +# model settings +model = dict( + type='FastRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + roi_head=dict( + type='StandardRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False)), + test_cfg=dict( + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100))) diff --git a/configs/_base_/models/faster_rcnn_r50_caffe_c4.py b/configs/_base_/models/faster_rcnn_r50_caffe_c4.py new file mode 100644 index 0000000..51b5db4 --- /dev/null +++ b/configs/_base_/models/faster_rcnn_r50_caffe_c4.py @@ -0,0 +1,114 @@ +# model settings +norm_cfg = dict(type='BN', requires_grad=False) +model = dict( + type='FasterRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=3, + strides=(1, 2, 2), + dilations=(1, 1, 1), + out_indices=(2, ), + frozen_stages=1, + norm_cfg=norm_cfg, + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + rpn_head=dict( + type='RPNHead', + in_channels=1024, + feat_channels=1024, + anchor_generator=dict( + type='AnchorGenerator', + scales=[2, 4, 8, 16, 32], + ratios=[0.5, 1.0, 2.0], + strides=[16]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + shared_head=dict( + type='ResLayer', + depth=50, + stage=3, + stride=2, + dilation=1, + style='caffe', + norm_cfg=norm_cfg, + norm_eval=True), + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=1024, + featmap_strides=[16]), + bbox_head=dict( + type='BBoxHead', + with_avg_pool=True, + roi_feat_size=7, + in_channels=2048, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=12000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=6000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100))) diff --git a/configs/_base_/models/faster_rcnn_r50_caffe_dc5.py b/configs/_base_/models/faster_rcnn_r50_caffe_dc5.py new file mode 100644 index 0000000..a377a6f --- /dev/null +++ b/configs/_base_/models/faster_rcnn_r50_caffe_dc5.py @@ -0,0 +1,105 @@ +# model settings +norm_cfg = dict(type='BN', requires_grad=False) +model = dict( + type='FasterRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + strides=(1, 2, 2, 1), + dilations=(1, 1, 1, 2), + out_indices=(3, ), + frozen_stages=1, + norm_cfg=norm_cfg, + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + rpn_head=dict( + type='RPNHead', + in_channels=2048, + feat_channels=2048, + anchor_generator=dict( + type='AnchorGenerator', + scales=[2, 4, 8, 16, 32], + ratios=[0.5, 1.0, 2.0], + strides=[16]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=2048, + featmap_strides=[16]), + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=2048, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=12000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms=dict(type='nms', iou_threshold=0.7), + nms_pre=6000, + max_per_img=1000, + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100))) diff --git a/configs/_base_/models/faster_rcnn_r50_fpn.py b/configs/_base_/models/faster_rcnn_r50_fpn.py new file mode 100644 index 0000000..1ef8e7b --- /dev/null +++ b/configs/_base_/models/faster_rcnn_r50_fpn.py @@ -0,0 +1,108 @@ +# model settings +model = dict( + type='FasterRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100) + # soft-nms is also supported for rcnn testing + # e.g., nms=dict(type='soft_nms', iou_threshold=0.5, min_score=0.05) + )) diff --git a/configs/_base_/models/mask_rcnn_r50_caffe_c4.py b/configs/_base_/models/mask_rcnn_r50_caffe_c4.py new file mode 100644 index 0000000..122202e --- /dev/null +++ b/configs/_base_/models/mask_rcnn_r50_caffe_c4.py @@ -0,0 +1,125 @@ +# model settings +norm_cfg = dict(type='BN', requires_grad=False) +model = dict( + type='MaskRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=3, + strides=(1, 2, 2), + dilations=(1, 1, 1), + out_indices=(2, ), + frozen_stages=1, + norm_cfg=norm_cfg, + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + rpn_head=dict( + type='RPNHead', + in_channels=1024, + feat_channels=1024, + anchor_generator=dict( + type='AnchorGenerator', + scales=[2, 4, 8, 16, 32], + ratios=[0.5, 1.0, 2.0], + strides=[16]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + shared_head=dict( + type='ResLayer', + depth=50, + stage=3, + stride=2, + dilation=1, + style='caffe', + norm_cfg=norm_cfg, + norm_eval=True), + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=1024, + featmap_strides=[16]), + bbox_head=dict( + type='BBoxHead', + with_avg_pool=True, + roi_feat_size=7, + in_channels=2048, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + mask_roi_extractor=None, + mask_head=dict( + type='FCNMaskHead', + num_convs=0, + in_channels=2048, + conv_out_channels=256, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=12000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=14, + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=6000, + nms=dict(type='nms', iou_threshold=0.7), + max_per_img=1000, + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100, + mask_thr_binary=0.5))) diff --git a/configs/_base_/models/mask_rcnn_r50_fpn.py b/configs/_base_/models/mask_rcnn_r50_fpn.py new file mode 100644 index 0000000..d903e55 --- /dev/null +++ b/configs/_base_/models/mask_rcnn_r50_fpn.py @@ -0,0 +1,120 @@ +# model settings +model = dict( + type='MaskRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + mask_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + mask_head=dict( + type='FCNMaskHead', + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100, + mask_thr_binary=0.5))) diff --git a/configs/_base_/models/retinanet_r50_fpn.py b/configs/_base_/models/retinanet_r50_fpn.py new file mode 100644 index 0000000..56e43fa --- /dev/null +++ b/configs/_base_/models/retinanet_r50_fpn.py @@ -0,0 +1,60 @@ +# model settings +model = dict( + type='RetinaNet', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_input', + num_outs=5), + bbox_head=dict( + type='RetinaHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=4, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[8, 16, 32, 64, 128]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + # model training and testing settings + train_cfg=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100)) diff --git a/configs/_base_/models/rpn_r50_caffe_c4.py b/configs/_base_/models/rpn_r50_caffe_c4.py new file mode 100644 index 0000000..8b32ca9 --- /dev/null +++ b/configs/_base_/models/rpn_r50_caffe_c4.py @@ -0,0 +1,58 @@ +# model settings +model = dict( + type='RPN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=3, + strides=(1, 2, 2), + dilations=(1, 1, 1), + out_indices=(2, ), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + neck=None, + rpn_head=dict( + type='RPNHead', + in_channels=1024, + feat_channels=1024, + anchor_generator=dict( + type='AnchorGenerator', + scales=[2, 4, 8, 16, 32], + ratios=[0.5, 1.0, 2.0], + strides=[16]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=12000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0))) diff --git a/configs/_base_/models/rpn_r50_fpn.py b/configs/_base_/models/rpn_r50_fpn.py new file mode 100644 index 0000000..edaf4d4 --- /dev/null +++ b/configs/_base_/models/rpn_r50_fpn.py @@ -0,0 +1,58 @@ +# model settings +model = dict( + type='RPN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=2000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0))) diff --git a/configs/_base_/models/ssd300.py b/configs/_base_/models/ssd300.py new file mode 100644 index 0000000..f17df01 --- /dev/null +++ b/configs/_base_/models/ssd300.py @@ -0,0 +1,56 @@ +# model settings +input_size = 300 +model = dict( + type='SingleStageDetector', + backbone=dict( + type='SSDVGG', + depth=16, + with_last_pool=False, + ceil_mode=True, + out_indices=(3, 4), + out_feature_indices=(22, 34), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://vgg16_caffe')), + neck=dict( + type='SSDNeck', + in_channels=(512, 1024), + out_channels=(512, 1024, 512, 256, 256, 256), + level_strides=(2, 2, 1, 1), + level_paddings=(1, 1, 0, 0), + l2_norm_scale=20), + bbox_head=dict( + type='SSDHead', + in_channels=(512, 1024, 512, 256, 256, 256), + num_classes=80, + anchor_generator=dict( + type='SSDAnchorGenerator', + scale_major=False, + input_size=input_size, + basesize_ratio_range=(0.15, 0.9), + strides=[8, 16, 32, 64, 100, 300], + ratios=[[2], [2, 3], [2, 3], [2, 3], [2], [2]]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.1, 0.1, 0.2, 0.2])), + # model training and testing settings + train_cfg=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0., + ignore_iof_thr=-1, + gt_max_assign_all=False), + smoothl1_beta=1., + allowed_border=-1, + pos_weight=-1, + neg_pos_ratio=3, + debug=False), + test_cfg=dict( + nms_pre=1000, + nms=dict(type='nms', iou_threshold=0.45), + min_bbox_size=0, + score_thr=0.02, + max_per_img=200)) +cudnn_benchmark = True diff --git a/configs/_base_/schedules/schedule_1x.py b/configs/_base_/schedules/schedule_1x.py new file mode 100644 index 0000000..13b3783 --- /dev/null +++ b/configs/_base_/schedules/schedule_1x.py @@ -0,0 +1,11 @@ +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[8, 11]) +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/_base_/schedules/schedule_20e.py b/configs/_base_/schedules/schedule_20e.py new file mode 100644 index 0000000..00e8590 --- /dev/null +++ b/configs/_base_/schedules/schedule_20e.py @@ -0,0 +1,11 @@ +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/_base_/schedules/schedule_2x.py b/configs/_base_/schedules/schedule_2x.py new file mode 100644 index 0000000..69dc9ee --- /dev/null +++ b/configs/_base_/schedules/schedule_2x.py @@ -0,0 +1,11 @@ +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/albu_example/README.md b/configs/albu_example/README.md new file mode 100644 index 0000000..b11ae56 --- /dev/null +++ b/configs/albu_example/README.md @@ -0,0 +1,19 @@ +# Albu Example + + + +``` +@article{2018arXiv180906839B, + author = {A. Buslaev, A. Parinov, E. Khvedchenya, V.~I. Iglovikov and A.~A. Kalinin}, + title = "{Albumentations: fast and flexible image augmentations}", + journal = {ArXiv e-prints}, + eprint = {1809.06839}, + year = 2018 +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50 | pytorch | 1x | 4.4 | 16.6 | 38.0 | 34.5 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/albu_example/mask_rcnn_r50_fpn_albu_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/albu_example/mask_rcnn_r50_fpn_albu_1x_coco/mask_rcnn_r50_fpn_albu_1x_coco_20200208-ab203bcd.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/albu_example/mask_rcnn_r50_fpn_albu_1x_coco/mask_rcnn_r50_fpn_albu_1x_coco_20200208_225520.log.json) | diff --git a/configs/albu_example/mask_rcnn_r50_fpn_albu_1x_coco.py b/configs/albu_example/mask_rcnn_r50_fpn_albu_1x_coco.py new file mode 100644 index 0000000..b3f879a --- /dev/null +++ b/configs/albu_example/mask_rcnn_r50_fpn_albu_1x_coco.py @@ -0,0 +1,73 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +albu_train_transforms = [ + dict( + type='ShiftScaleRotate', + shift_limit=0.0625, + scale_limit=0.0, + rotate_limit=0, + interpolation=1, + p=0.5), + dict( + type='RandomBrightnessContrast', + brightness_limit=[0.1, 0.3], + contrast_limit=[0.1, 0.3], + p=0.2), + dict( + type='OneOf', + transforms=[ + dict( + type='RGBShift', + r_shift_limit=10, + g_shift_limit=10, + b_shift_limit=10, + p=1.0), + dict( + type='HueSaturationValue', + hue_shift_limit=20, + sat_shift_limit=30, + val_shift_limit=20, + p=1.0) + ], + p=0.1), + dict(type='JpegCompression', quality_lower=85, quality_upper=95, p=0.2), + dict(type='ChannelShuffle', p=0.1), + dict( + type='OneOf', + transforms=[ + dict(type='Blur', blur_limit=3, p=1.0), + dict(type='MedianBlur', blur_limit=3, p=1.0) + ], + p=0.1), +] +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + dict(type='Pad', size_divisor=32), + dict( + type='Albu', + transforms=albu_train_transforms, + bbox_params=dict( + type='BboxParams', + format='pascal_voc', + label_fields=['gt_labels'], + min_visibility=0.0, + filter_lost_elements=True), + keymap={ + 'img': 'image', + 'gt_masks': 'masks', + 'gt_bboxes': 'bboxes' + }, + update_pad_shape=False, + skip_img_without_anno=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks'], + meta_keys=('filename', 'ori_shape', 'img_shape', 'img_norm_cfg', + 'pad_shape', 'scale_factor')) +] +data = dict(train=dict(pipeline=train_pipeline)) diff --git a/configs/atss/README.md b/configs/atss/README.md new file mode 100644 index 0000000..8aa7746 --- /dev/null +++ b/configs/atss/README.md @@ -0,0 +1,21 @@ +# Bridging the Gap Between Anchor-based and Anchor-free Detection via Adaptive Training Sample Selection + +## Introduction + + + +```latex +@article{zhang2019bridging, + title = {Bridging the Gap Between Anchor-based and Anchor-free Detection via Adaptive Training Sample Selection}, + author = {Zhang, Shifeng and Chi, Cheng and Yao, Yongqiang and Lei, Zhen and Li, Stan Z.}, + journal = {arXiv preprint arXiv:1912.02424}, + year = {2019} +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | pytorch | 1x | 3.7 | 19.7 | 39.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/atss/atss_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/atss/atss_r50_fpn_1x_coco/atss_r50_fpn_1x_coco_20200209-985f7bd0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/atss/atss_r50_fpn_1x_coco/atss_r50_fpn_1x_coco_20200209_102539.log.json) | +| R-101 | pytorch | 1x | 5.6 | 12.3 | 41.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/atss/atss_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/atss/atss_r101_fpn_1x_coco/atss_r101_fpn_1x_20200825-dfcadd6f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/atss/atss_r101_fpn_1x_coco/atss_r101_fpn_1x_20200825-dfcadd6f.log.json) | diff --git a/configs/atss/atss_r101_fpn_1x_coco.py b/configs/atss/atss_r101_fpn_1x_coco.py new file mode 100644 index 0000000..5225d2a --- /dev/null +++ b/configs/atss/atss_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './atss_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/atss/atss_r50_fpn_1x_coco.py b/configs/atss/atss_r50_fpn_1x_coco.py new file mode 100644 index 0000000..42ff4c5 --- /dev/null +++ b/configs/atss/atss_r50_fpn_1x_coco.py @@ -0,0 +1,62 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='ATSS', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5), + bbox_head=dict( + type='ATSSHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + octave_base_scale=8, + scales_per_octave=1, + strides=[8, 16, 32, 64, 128]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.1, 0.1, 0.2, 0.2]), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='GIoULoss', loss_weight=2.0), + loss_centerness=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), + # training and testing settings + train_cfg=dict( + assigner=dict(type='ATSSAssigner', topk=9), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/atss/metafile.yml b/configs/atss/metafile.yml new file mode 100644 index 0000000..f4c567e --- /dev/null +++ b/configs/atss/metafile.yml @@ -0,0 +1,60 @@ +Collections: + - Name: ATSS + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - ATSS + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/1912.02424 + Title: 'Bridging the Gap Between Anchor-based and Anchor-free Detection via Adaptive Training Sample Selection' + README: configs/atss/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/atss.py#L6 + Version: v2.0.0 + +Models: + - Name: atss_r50_fpn_1x_coco + In Collection: ATSS + Config: configs/atss/atss_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.7 + inference time (ms/im): + - value: 50.76 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/atss/atss_r50_fpn_1x_coco/atss_r50_fpn_1x_coco_20200209-985f7bd0.pth + + - Name: atss_r101_fpn_1x_coco + In Collection: ATSS + Config: configs/atss/atss_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.6 + inference time (ms/im): + - value: 81.3 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/atss/atss_r101_fpn_1x_coco/atss_r101_fpn_1x_20200825-dfcadd6f.pth diff --git a/configs/autoassign/README.md b/configs/autoassign/README.md new file mode 100644 index 0000000..4d5f376 --- /dev/null +++ b/configs/autoassign/README.md @@ -0,0 +1,25 @@ +# AutoAssign: Differentiable Label Assignment for Dense Object Detection + +## Introduction + + + +``` +@article{zhu2020autoassign, + title={AutoAssign: Differentiable Label Assignment for Dense Object Detection}, + author={Zhu, Benjin and Wang, Jianfeng and Jiang, Zhengkai and Zong, Fuhang and Liu, Songtao and Li, Zeming and Sun, Jian}, + journal={arXiv preprint arXiv:2007.03496}, + year={2020} +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Mem (GB) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:------:|:------:|:--------:| +| R-50 | caffe | 1x | 4.08 | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/autoassign/autoassign_r50_fpn_8x2_1x_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/autoassign/auto_assign_r50_fpn_1x_coco/auto_assign_r50_fpn_1x_coco_20210413_115540-5e17991f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/autoassign/auto_assign_r50_fpn_1x_coco/auto_assign_r50_fpn_1x_coco_20210413_115540-5e17991f.log.json) | + +**Note**: + +1. We find that the performance is unstable with 1x setting and may fluctuate by about 0.3 mAP. mAP 40.3 ~ 40.6 is acceptable. Such fluctuation can also be found in the original implementation. +2. You can get a more stable results ~ mAP 40.6 with a schedule total 13 epoch, and learning rate is divided by 10 at 10th and 13th epoch. diff --git a/configs/autoassign/autoassign_r50_fpn_8x2_1x_coco.py b/configs/autoassign/autoassign_r50_fpn_8x2_1x_coco.py new file mode 100644 index 0000000..db548dc --- /dev/null +++ b/configs/autoassign/autoassign_r50_fpn_8x2_1x_coco.py @@ -0,0 +1,85 @@ +# We follow the original implementation which +# adopts the Caffe pre-trained backbone. +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='AutoAssign', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs=True, + num_outs=5, + relu_before_extra_convs=True, + init_cfg=dict(type='Caffe2Xavier', layer='Conv2d')), + bbox_head=dict( + type='AutoAssignHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + strides=[8, 16, 32, 64, 128], + loss_bbox=dict(type='GIoULoss', loss_weight=5.0)), + train_cfg=None, + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) +img_norm_cfg = dict( + mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(lr=0.01, paramwise_cfg=dict(norm_decay_mult=0.)) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=1000, + warmup_ratio=1.0 / 1000, + step=[8, 11]) +total_epochs = 12 diff --git a/configs/autoassign/metafile.yml b/configs/autoassign/metafile.yml new file mode 100644 index 0000000..f1e9051 --- /dev/null +++ b/configs/autoassign/metafile.yml @@ -0,0 +1,33 @@ +Collections: + - Name: AutoAssign + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - AutoAssign + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/2007.03496 + Title: 'AutoAssign: Differentiable Label Assignment for Dense Object Detection' + README: configs/autoassign/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.12.0/mmdet/models/detectors/autoassign.py#L6 + Version: v2.12.0 + +Models: + - Name: autoassign_r50_fpn_8x2_1x_coco + In Collection: AutoAssign + Config: configs/autoassign/autoassign_r50_fpn_8x2_1x_coco.py + Metadata: + Training Memory (GB): 4.08 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/autoassign/auto_assign_r50_fpn_1x_coco/auto_assign_r50_fpn_1x_coco_20210413_115540-5e17991f.pth diff --git a/configs/carafe/README.md b/configs/carafe/README.md new file mode 100644 index 0000000..768cb98 --- /dev/null +++ b/configs/carafe/README.md @@ -0,0 +1,32 @@ +# CARAFE: Content-Aware ReAssembly of FEatures + +## Introduction + + + +We provide config files to reproduce the object detection & instance segmentation results in the ICCV 2019 Oral paper for [CARAFE: Content-Aware ReAssembly of FEatures](https://arxiv.org/abs/1905.02188). + +``` +@inproceedings{Wang_2019_ICCV, + title = {CARAFE: Content-Aware ReAssembly of FEatures}, + author = {Wang, Jiaqi and Chen, Kai and Xu, Rui and Liu, Ziwei and Loy, Chen Change and Lin, Dahua}, + booktitle = {The IEEE International Conference on Computer Vision (ICCV)}, + month = {October}, + year = {2019} +} +``` + +## Results and Models + +The results on COCO 2017 val is shown in the below table. + +| Method | Backbone | Style | Lr schd | Test Proposal Num | Inf time (fps) | Box AP | Mask AP | Config | Download | +|:--------------------:|:--------:|:-------:|:-------:|:-----------------:|:--------------:|:------:|:-------:|:------:|:--------:| +| Faster R-CNN w/ CARAFE | R-50-FPN | pytorch | 1x | 1000 | 16.5 | 38.6 | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/carafe/faster_rcnn_r50_fpn_carafe_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/carafe/faster_rcnn_r50_fpn_carafe_1x_coco/faster_rcnn_r50_fpn_carafe_1x_coco_bbox_mAP-0.386_20200504_175733-385a75b7.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/carafe/faster_rcnn_r50_fpn_carafe_1x_coco/faster_rcnn_r50_fpn_carafe_1x_coco_20200504_175733.log.json) | +| - | - | - | - | 2000 | | | | | +| Mask R-CNN w/ CARAFE | R-50-FPN | pytorch | 1x | 1000 | 14.0 | 39.3 | 35.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/carafe/mask_rcnn_r50_fpn_carafe_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/carafe/mask_rcnn_r50_fpn_carafe_1x_coco/mask_rcnn_r50_fpn_carafe_1x_coco_bbox_mAP-0.393__segm_mAP-0.358_20200503_135957-8687f195.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/carafe/mask_rcnn_r50_fpn_carafe_1x_coco/mask_rcnn_r50_fpn_carafe_1x_coco_20200503_135957.log.json) | +| - | - | - | - | 2000 | | | | | + +## Implementation + +The CUDA implementation of CARAFE can be find at https://github.com/myownskyW7/CARAFE. diff --git a/configs/carafe/faster_rcnn_r50_fpn_carafe_1x_coco.py b/configs/carafe/faster_rcnn_r50_fpn_carafe_1x_coco.py new file mode 100644 index 0000000..dedac3f --- /dev/null +++ b/configs/carafe/faster_rcnn_r50_fpn_carafe_1x_coco.py @@ -0,0 +1,50 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + neck=dict( + type='FPN_CARAFE', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5, + start_level=0, + end_level=-1, + norm_cfg=None, + act_cfg=None, + order=('conv', 'norm', 'act'), + upsample_cfg=dict( + type='carafe', + up_kernel=5, + up_group=1, + encoder_kernel=3, + encoder_dilation=1, + compressed_channels=64))) +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=(1333, 800), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/carafe/mask_rcnn_r50_fpn_carafe_1x_coco.py b/configs/carafe/mask_rcnn_r50_fpn_carafe_1x_coco.py new file mode 100644 index 0000000..668c023 --- /dev/null +++ b/configs/carafe/mask_rcnn_r50_fpn_carafe_1x_coco.py @@ -0,0 +1,60 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + neck=dict( + type='FPN_CARAFE', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5, + start_level=0, + end_level=-1, + norm_cfg=None, + act_cfg=None, + order=('conv', 'norm', 'act'), + upsample_cfg=dict( + type='carafe', + up_kernel=5, + up_group=1, + encoder_kernel=3, + encoder_dilation=1, + compressed_channels=64)), + roi_head=dict( + mask_head=dict( + upsample_cfg=dict( + type='carafe', + scale_factor=2, + up_kernel=5, + up_group=1, + encoder_kernel=3, + encoder_dilation=1, + compressed_channels=64)))) +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, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/cascade_rcnn/README.md b/configs/cascade_rcnn/README.md new file mode 100644 index 0000000..7d18ab1 --- /dev/null +++ b/configs/cascade_rcnn/README.md @@ -0,0 +1,69 @@ +# Cascade R-CNN: High Quality Object Detection and Instance Segmentation + +## Introduction + + + +```latex +@article{Cai_2019, + title={Cascade R-CNN: High Quality Object Detection and Instance Segmentation}, + ISSN={1939-3539}, + url={http://dx.doi.org/10.1109/tpami.2019.2956516}, + DOI={10.1109/tpami.2019.2956516}, + journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, + publisher={Institute of Electrical and Electronics Engineers (IEEE)}, + author={Cai, Zhaowei and Vasconcelos, Nuno}, + year={2019}, + pages={1–1} +} +``` + +## Results and models + +### Cascade R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: |:------:|:--------:| +| R-50-FPN | caffe | 1x | 4.2 | | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco/cascade_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.404_20200504_174853-b857be87.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco/cascade_rcnn_r50_caffe_fpn_1x_coco_20200504_174853.log.json) | +| R-50-FPN | pytorch | 1x | 4.4 | 16.1 | 40.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco/cascade_rcnn_r50_fpn_1x_coco_20200316-3dc56deb.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco/cascade_rcnn_r50_fpn_1x_coco_20200316_214748.log.json) | +| R-50-FPN | pytorch | 20e | - | - | 41.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco/cascade_rcnn_r50_fpn_20e_coco_bbox_mAP-0.41_20200504_175131-e9872a90.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco/cascade_rcnn_r50_fpn_20e_coco_20200504_175131.log.json) | +| R-101-FPN | caffe | 1x | 6.2 | | 42.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco/cascade_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.423_20200504_175649-cab8dbd5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco/cascade_rcnn_r101_caffe_fpn_1x_coco_20200504_175649.log.json) | +| R-101-FPN | pytorch | 1x | 6.4 | 13.5 | 42.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco/cascade_rcnn_r101_fpn_1x_coco_20200317-0b6a2fbf.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco/cascade_rcnn_r101_fpn_1x_coco_20200317_101744.log.json) | +| R-101-FPN | pytorch | 20e | - | - | 42.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco/cascade_rcnn_r101_fpn_20e_coco_bbox_mAP-0.425_20200504_231812-5057dcc5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco/cascade_rcnn_r101_fpn_20e_coco_20200504_231812.log.json) | +| X-101-32x4d-FPN | pytorch | 1x | 7.6 | 10.9 | 43.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco/cascade_rcnn_x101_32x4d_fpn_1x_coco_20200316-95c2deb6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco/cascade_rcnn_x101_32x4d_fpn_1x_coco_20200316_055608.log.json) | +| X-101-32x4d-FPN | pytorch | 20e | 7.6 | | 43.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco/cascade_rcnn_x101_32x4d_fpn_20e_coco_20200906_134608-9ae0a720.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco/cascade_rcnn_x101_32x4d_fpn_20e_coco_20200906_134608.log.json) | +| X-101-64x4d-FPN | pytorch | 1x | 10.7 | | 44.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco/cascade_rcnn_x101_64x4d_fpn_1x_coco_20200515_075702-43ce6a30.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco/cascade_rcnn_x101_64x4d_fpn_1x_coco_20200515_075702.log.json) | +| X-101-64x4d-FPN | pytorch | 20e | 10.7 | | 44.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco/cascade_rcnn_x101_64x4d_fpn_20e_coco_20200509_224357-051557b1.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco/cascade_rcnn_x101_64x4d_fpn_20e_coco_20200509_224357.log.json)| + +### Cascade Mask R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| R-50-FPN | caffe | 1x | 5.9 | | 41.2 | 36.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco/cascade_mask_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.412__segm_mAP-0.36_20200504_174659-5004b251.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco/cascade_mask_rcnn_r50_caffe_fpn_1x_coco_20200504_174659.log.json) | +| R-50-FPN | pytorch | 1x | 6.0 | 11.2 | 41.2 | 35.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco/cascade_mask_rcnn_r50_fpn_1x_coco_20200203-9d4dcb24.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco/cascade_mask_rcnn_r50_fpn_1x_coco_20200203_170449.log.json) | +| R-50-FPN | pytorch | 20e | - | - | 41.9 | 36.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco/cascade_mask_rcnn_r50_fpn_20e_coco_bbox_mAP-0.419__segm_mAP-0.365_20200504_174711-4af8e66e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco/cascade_mask_rcnn_r50_fpn_20e_coco_20200504_174711.log.json)| +| R-101-FPN | caffe | 1x | 7.8 | | 43.2 | 37.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco/cascade_mask_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.432__segm_mAP-0.376_20200504_174813-5c1e9599.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco/cascade_mask_rcnn_r101_caffe_fpn_1x_coco_20200504_174813.log.json)| +| R-101-FPN | pytorch | 1x | 7.9 | 9.8 | 42.9 | 37.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco/cascade_mask_rcnn_r101_fpn_1x_coco_20200203-befdf6ee.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco/cascade_mask_rcnn_r101_fpn_1x_coco_20200203_092521.log.json) | +| R-101-FPN | pytorch | 20e | - | - | 43.4 | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco/cascade_mask_rcnn_r101_fpn_20e_coco_bbox_mAP-0.434__segm_mAP-0.378_20200504_174836-005947da.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco/cascade_mask_rcnn_r101_fpn_20e_coco_20200504_174836.log.json)| +| X-101-32x4d-FPN | pytorch | 1x | 9.2 | 8.6 | 44.3 | 38.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco_20200201-0f411b1f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco_20200201_052416.log.json) | +| X-101-32x4d-FPN | pytorch | 20e | 9.2 | - | 45.0 | 39.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco_20200528_083917-ed1f4751.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco_20200528_083917.log.json) | +| X-101-64x4d-FPN | pytorch | 1x | 12.2 | 6.7 | 45.3 | 39.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco_20200203-9a2db89d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco_20200203_044059.log.json) | +| X-101-64x4d-FPN | pytorch | 20e | 12.2 | | 45.6 |39.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco_20200512_161033-bdb5126a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco_20200512_161033.log.json)| + +**Notes:** + +- The `20e` schedule in Cascade (Mask) R-CNN indicates decreasing the lr at 16 and 19 epochs, with a total of 20 epochs. + +## Pre-trained Models + +We also train some models with longer schedules and multi-scale training for Cascade Mask R-CNN. The users could finetune them for downstream tasks. + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :----------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| R-50-FPN | caffe | 3x | 5.7 | | 44.0 | 38.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210707_002651-6e29b3a6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210707_002651.log.json) +| R-50-FPN | pytorch| 3x | 5.9 | | 44.3 | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco_20210628_164719-5bdc3824.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco_20210628_164719.log.json) +| R-101-FPN | caffe | 3x | 7.7 | | 45.4 | 39.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco_20210707_002620-a5bd2389.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco_20210707_002620.log.json) +| R-101-FPN | pytorch| 3x | 7.8 | | 45.5 | 39.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco_20210628_165236-51a2d363.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco_20210628_165236.log.json) +| X-101-32x4d-FPN | pytorch| 3x | 9.0 | | 46.3 | 40.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco_20210706_225234-40773067.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco_20210706_225234.log.json) +| X-101-32x8d-FPN | pytorch| 3x | 12.1 | | 46.1 | 39.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco_20210719_180640-9ff7e76f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco_20210719_180640.log.json) +| X-101-64x4d-FPN | pytorch| 3x | 12.0 | | 46.6 | 40.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco_20210719_210311-d3e64ba0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco_20210719_210311.log.json) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..5ee6231 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..1df87fc --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py @@ -0,0 +1,7 @@ +_base_ = './cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..f59c155 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco.py new file mode 100644 index 0000000..45ab7ed --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco.py @@ -0,0 +1,6 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_20e_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..1b20f16 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco.py @@ -0,0 +1,6 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..12d37ef --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,41 @@ +_base_ = ['./cascade_mask_rcnn_r50_fpn_1x_coco.py'] + +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..9fb817e --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py @@ -0,0 +1,49 @@ +_base_ = ['./cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py'] +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) + +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..49ab539 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/cascade_mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco.py new file mode 100644 index 0000000..1296dc4 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/cascade_mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_20e.py', '../_base_/default_runtime.py' +] diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..ed0c6d1 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py @@ -0,0 +1,4 @@ +_base_ = [ + '../common/mstrain_3x_coco_instance.py', + '../_base_/models/cascade_mask_rcnn_r50_fpn.py' +] diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..06cbbe7 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco.py new file mode 100644 index 0000000..4e35236 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_20e_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..7d37d17 --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..eeec1aa --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py @@ -0,0 +1,60 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py' + +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=8, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + style='pytorch', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnext101_32x8d'))) + +# ResNeXt-101-32x8d model trained with Caffe2 at FB, +# so the mean and std need to be changed. +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], + std=[57.375, 57.120, 58.395], + to_rgb=False) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..7dbef5f --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco.py new file mode 100644 index 0000000..579b1ac --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_20e_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py b/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..ed6cf4b --- /dev/null +++ b/configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..1e90f4b --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './cascade_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..5c07776 --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './cascade_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py new file mode 100644 index 0000000..b1719c2 --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py @@ -0,0 +1,6 @@ +_base_ = './cascade_rcnn_r50_fpn_20e_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..696bcfb --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,42 @@ +_base_ = './cascade_rcnn_r50_fpn_1x_coco.py' + +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) + +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..87e21fb --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/cascade_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] diff --git a/configs/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco.py new file mode 100644 index 0000000..6f886e1 --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco.py @@ -0,0 +1,4 @@ +_base_ = './cascade_rcnn_r50_fpn_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..5ac02c1 --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco.py new file mode 100644 index 0000000..486e45e --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_rcnn_r50_fpn_20e_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco.py b/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..78229f0 --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,15 @@ +_base_ = './cascade_rcnn_r50_fpn_1x_coco.py' +model = dict( + type='CascadeRCNN', + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco.py b/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco.py new file mode 100644 index 0000000..58812de --- /dev/null +++ b/configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco.py @@ -0,0 +1,15 @@ +_base_ = './cascade_rcnn_r50_fpn_20e_coco.py' +model = dict( + type='CascadeRCNN', + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/cascade_rcnn/metafile.yml b/configs/cascade_rcnn/metafile.yml new file mode 100644 index 0000000..1007f2e --- /dev/null +++ b/configs/cascade_rcnn/metafile.yml @@ -0,0 +1,525 @@ +Collections: + - Name: Cascade R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Cascade R-CNN + - FPN + - RPN + - ResNet + - RoIAlign + Paper: + URL: http://dx.doi.org/10.1109/tpami.2019.2956516 + Title: 'Cascade R-CNN: Delving into High Quality Object Detection' + README: configs/cascade_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/cascade_rcnn.py#L6 + Version: v2.0.0 + +Models: + - Name: cascade_rcnn_r50_caffe_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.2 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_caffe_fpn_1x_coco/cascade_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.404_20200504_174853-b857be87.pth + + - Name: cascade_rcnn_r50_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.4 + inference time (ms/im): + - value: 62.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco/cascade_rcnn_r50_fpn_1x_coco_20200316-3dc56deb.pth + + - Name: cascade_rcnn_r50_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco.py + Metadata: + Training Memory (GB): 4.4 + inference time (ms/im): + - value: 62.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r50_fpn_20e_coco/cascade_rcnn_r50_fpn_20e_coco_bbox_mAP-0.41_20200504_175131-e9872a90.pth + + - Name: cascade_rcnn_r101_caffe_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.2 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_caffe_fpn_1x_coco/cascade_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.423_20200504_175649-cab8dbd5.pth + + - Name: cascade_rcnn_r101_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.4 + inference time (ms/im): + - value: 74.07 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco/cascade_rcnn_r101_fpn_1x_coco_20200317-0b6a2fbf.pth + + - Name: cascade_rcnn_r101_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco.py + Metadata: + Training Memory (GB): 6.4 + inference time (ms/im): + - value: 74.07 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_r101_fpn_20e_coco/cascade_rcnn_r101_fpn_20e_coco_bbox_mAP-0.425_20200504_231812-5057dcc5.pth + + - Name: cascade_rcnn_x101_32x4d_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.6 + inference time (ms/im): + - value: 91.74 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_1x_coco/cascade_rcnn_x101_32x4d_fpn_1x_coco_20200316-95c2deb6.pth + + - Name: cascade_rcnn_x101_32x4d_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco.py + Metadata: + Training Memory (GB): 7.6 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_32x4d_fpn_20e_coco/cascade_rcnn_x101_32x4d_fpn_20e_coco_20200906_134608-9ae0a720.pth + + - Name: cascade_rcnn_x101_64x4d_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 10.7 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_1x_coco/cascade_rcnn_x101_64x4d_fpn_1x_coco_20200515_075702-43ce6a30.pth + + - Name: cascade_rcnn_x101_64x4d_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco.py + Metadata: + Training Memory (GB): 10.7 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_rcnn_x101_64x4d_fpn_20e_coco/cascade_rcnn_x101_64x4d_fpn_20e_coco_20200509_224357-051557b1.pth + + - Name: cascade_mask_rcnn_r50_caffe_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.9 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_1x_coco/cascade_mask_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.412__segm_mAP-0.36_20200504_174659-5004b251.pth + + - Name: cascade_mask_rcnn_r50_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 89.29 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 35.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco/cascade_mask_rcnn_r50_fpn_1x_coco_20200203-9d4dcb24.pth + + - Name: cascade_mask_rcnn_r50_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 89.29 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_20e_coco/cascade_mask_rcnn_r50_fpn_20e_coco_bbox_mAP-0.419__segm_mAP-0.365_20200504_174711-4af8e66e.pth + + - Name: cascade_mask_rcnn_r101_caffe_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.8 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_1x_coco/cascade_mask_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.432__segm_mAP-0.376_20200504_174813-5c1e9599.pth + + - Name: cascade_mask_rcnn_r101_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.9 + inference time (ms/im): + - value: 102.04 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco/cascade_mask_rcnn_r101_fpn_1x_coco_20200203-befdf6ee.pth + + - Name: cascade_mask_rcnn_r101_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco.py + Metadata: + Training Memory (GB): 7.9 + inference time (ms/im): + - value: 102.04 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_20e_coco/cascade_mask_rcnn_r101_fpn_20e_coco_bbox_mAP-0.434__segm_mAP-0.378_20200504_174836-005947da.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 9.2 + inference time (ms/im): + - value: 116.28 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco_20200201-0f411b1f.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco.py + Metadata: + Training Memory (GB): 9.2 + inference time (ms/im): + - value: 116.28 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco/cascade_mask_rcnn_x101_32x4d_fpn_20e_coco_20200528_083917-ed1f4751.pth + + - Name: cascade_mask_rcnn_x101_64x4d_fpn_1x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 12.2 + inference time (ms/im): + - value: 149.25 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco/cascade_mask_rcnn_x101_64x4d_fpn_1x_coco_20200203-9a2db89d.pth + + - Name: cascade_mask_rcnn_x101_64x4d_fpn_20e_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco.py + Metadata: + Training Memory (GB): 12.2 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco/cascade_mask_rcnn_x101_64x4d_fpn_20e_coco_20200512_161033-bdb5126a.pth + + - Name: cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.7 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco/cascade_mask_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210707_002651-6e29b3a6.pth + + - Name: cascade_mask_rcnn_r50_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.9 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco_20210628_164719-5bdc3824.pth + + - Name: cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 7.7 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco/cascade_mask_rcnn_r101_caffe_fpn_mstrain_3x_coco_20210707_002620-a5bd2389.pth + + - Name: cascade_mask_rcnn_r101_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 7.8 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco/cascade_mask_rcnn_r101_fpn_mstrain_3x_coco_20210628_165236-51a2d363.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 9.0 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_32x4d_fpn_mstrain_3x_coco_20210706_225234-40773067.pth + + - Name: cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 12.1 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_32x8d_fpn_mstrain_3x_coco_20210719_180640-9ff7e76f.pth + + - Name: cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco + In Collection: Cascade R-CNN + Config: configs/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 12.0 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cascade_rcnn/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco/cascade_mask_rcnn_x101_64x4d_fpn_mstrain_3x_coco_20210719_210311-d3e64ba0.pth diff --git a/configs/cascade_rpn/README.md b/configs/cascade_rpn/README.md new file mode 100644 index 0000000..5e1e60a --- /dev/null +++ b/configs/cascade_rpn/README.md @@ -0,0 +1,29 @@ +# Cascade RPN + + + +We provide the code for reproducing experiment results of [Cascade RPN](https://arxiv.org/abs/1909.06720). + +``` +@inproceedings{vu2019cascade, + title={Cascade RPN: Delving into High-Quality Region Proposal Network with Adaptive Convolution}, + author={Vu, Thang and Jang, Hyunjun and Pham, Trung X and Yoo, Chang D}, + booktitle={Conference on Neural Information Processing Systems (NeurIPS)}, + year={2019} +} +``` + +## Benchmark + +### Region proposal performance + +| Method | Backbone | Style | Mem (GB) | Train time (s/iter) | Inf time (fps) | AR 1000 | Config | Download | +|:------:|:--------:|:-----:|:--------:|:-------------------:|:--------------:|:-------:|:-------:|:--------------------------------------:| +| CRPN | R-50-FPN | caffe | - | - | - | 72.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rpn/crpn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rpn/crpn_r50_caffe_fpn_1x_coco/cascade_rpn_r50_caffe_fpn_1x_coco-7aa93cef.pth) | + +### Detection performance + +| Method | Proposal | Backbone | Style | Schedule | Mem (GB) | Train time (s/iter) | Inf time (fps) | box AP | Config | Download | +|:-------------:|:-----------:|:--------:|:-------:|:--------:|:--------:|:-------------------:|:--------------:|:------:|:-------:|:--------------------------------------------:| +| Fast R-CNN | Cascade RPN | R-50-FPN | caffe | 1x | - | - | - | 39.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rpn/crpn_fast_rcnn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rpn/crpn_fast_rcnn_r50_caffe_fpn_1x_coco/crpn_fast_rcnn_r50_caffe_fpn_1x_coco-cb486e66.pth) | +| Faster R-CNN | Cascade RPN | R-50-FPN | caffe | 1x | - | - | - | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco/crpn_faster_rcnn_r50_caffe_fpn_1x_coco-c8283cca.pth) | diff --git a/configs/cascade_rpn/crpn_fast_rcnn_r50_caffe_fpn_1x_coco.py b/configs/cascade_rpn/crpn_fast_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..29f5d07 --- /dev/null +++ b/configs/cascade_rpn/crpn_fast_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,77 @@ +_base_ = '../fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + roi_head=dict( + bbox_head=dict( + bbox_coder=dict(target_stds=[0.04, 0.04, 0.08, 0.08]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.5), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rcnn=dict( + assigner=dict( + pos_iou_thr=0.65, neg_iou_thr=0.65, min_pos_iou=0.65), + sampler=dict(num=256))), + test_cfg=dict(rcnn=dict(score_thr=1e-3))) +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=300), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'proposals', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=300), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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='ToTensor', keys=['proposals']), + dict( + type='ToDataContainer', + fields=[dict(key='proposals', stack=False)]), + dict(type='Collect', keys=['img', 'proposals']), + ]) +] +data = dict( + train=dict( + proposal_file=data_root + + 'proposals/crpn_r50_caffe_fpn_1x_train2017.pkl', + pipeline=train_pipeline), + val=dict( + proposal_file=data_root + + 'proposals/crpn_r50_caffe_fpn_1x_val2017.pkl', + pipeline=test_pipeline), + test=dict( + proposal_file=data_root + + 'proposals/crpn_r50_caffe_fpn_1x_val2017.pkl', + pipeline=test_pipeline)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco.py b/configs/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..bad86e6 --- /dev/null +++ b/configs/cascade_rpn/crpn_faster_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,92 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py' +rpn_weight = 0.7 +model = dict( + rpn_head=dict( + _delete_=True, + type='CascadeRPNHead', + num_stages=2, + stages=[ + dict( + type='StageCascadeRPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[1.0], + strides=[4, 8, 16, 32, 64]), + adapt_cfg=dict(type='dilation', dilation=3), + bridged_feature=True, + sampling=False, + with_cls=False, + reg_decoded_bbox=True, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=(.0, .0, .0, .0), + target_stds=(0.1, 0.1, 0.5, 0.5)), + loss_bbox=dict( + type='IoULoss', linear=True, + loss_weight=10.0 * rpn_weight)), + dict( + type='StageCascadeRPNHead', + in_channels=256, + feat_channels=256, + adapt_cfg=dict(type='offset'), + bridged_feature=False, + sampling=True, + with_cls=True, + reg_decoded_bbox=True, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=(.0, .0, .0, .0), + target_stds=(0.05, 0.05, 0.1, 0.1)), + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=True, + loss_weight=1.0 * rpn_weight), + loss_bbox=dict( + type='IoULoss', linear=True, + loss_weight=10.0 * rpn_weight)) + ]), + roi_head=dict( + bbox_head=dict( + bbox_coder=dict(target_stds=[0.04, 0.04, 0.08, 0.08]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.5), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=[ + dict( + assigner=dict( + type='RegionAssigner', center_ratio=0.2, ignore_ratio=0.5), + allowed_border=-1, + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.7, + min_pos_iou=0.3, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + pos_weight=-1, + debug=False) + ], + rpn_proposal=dict(max_per_img=300, nms=dict(iou_threshold=0.8)), + rcnn=dict( + assigner=dict( + pos_iou_thr=0.65, neg_iou_thr=0.65, min_pos_iou=0.65), + sampler=dict(type='RandomSampler', num=256))), + test_cfg=dict( + rpn=dict(max_per_img=300, nms=dict(iou_threshold=0.8)), + rcnn=dict(score_thr=1e-3))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/cascade_rpn/crpn_r50_caffe_fpn_1x_coco.py b/configs/cascade_rpn/crpn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..5562e69 --- /dev/null +++ b/configs/cascade_rpn/crpn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,77 @@ +_base_ = '../rpn/rpn_r50_caffe_fpn_1x_coco.py' +model = dict( + rpn_head=dict( + _delete_=True, + type='CascadeRPNHead', + num_stages=2, + stages=[ + dict( + type='StageCascadeRPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[1.0], + strides=[4, 8, 16, 32, 64]), + adapt_cfg=dict(type='dilation', dilation=3), + bridged_feature=True, + sampling=False, + with_cls=False, + reg_decoded_bbox=True, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=(.0, .0, .0, .0), + target_stds=(0.1, 0.1, 0.5, 0.5)), + loss_bbox=dict(type='IoULoss', linear=True, loss_weight=10.0)), + dict( + type='StageCascadeRPNHead', + in_channels=256, + feat_channels=256, + adapt_cfg=dict(type='offset'), + bridged_feature=False, + sampling=True, + with_cls=True, + reg_decoded_bbox=True, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=(.0, .0, .0, .0), + target_stds=(0.05, 0.05, 0.1, 0.1)), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, + loss_weight=1.0), + loss_bbox=dict(type='IoULoss', linear=True, loss_weight=10.0)) + ]), + train_cfg=dict(rpn=[ + dict( + assigner=dict( + type='RegionAssigner', center_ratio=0.2, ignore_ratio=0.5), + allowed_border=-1, + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.7, + min_pos_iou=0.3, + ignore_iof_thr=-1, + iou_calculator=dict(type='BboxOverlaps2D')), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + pos_weight=-1, + debug=False) + ]), + test_cfg=dict( + rpn=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.8), + min_bbox_size=0))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/centernet/README.md b/configs/centernet/README.md new file mode 100644 index 0000000..a1fcf3b --- /dev/null +++ b/configs/centernet/README.md @@ -0,0 +1,30 @@ +# CenterNet + +## Introduction + + + +```latex +@article{zhou2019objects, + title={Objects as Points}, + author={Zhou, Xingyi and Wang, Dequan and Kr{\"a}henb{\"u}hl, Philipp}, + booktitle={arXiv preprint arXiv:1904.07850}, + year={2019} +} +``` + +## Results and models + +| Backbone | DCN | Mem (GB) | Box AP | Flip box AP| Config | Download | +| :-------------: | :--------: |:----------------: | :------: | :------------: | :----: | :----: | +| ResNet-18 | N | 3.45 | 25.9 | 27.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/centernet/centernet_resnet18_140e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/centernet/centernet_resnet18_140e_coco/centernet_resnet18_140e_coco_20210705_093630-bb5b3bf7.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/centernet/centernet_resnet18_140e_coco/centernet_resnet18_140e_coco_20210705_093630.log.json) | +| ResNet-18 | Y | 3.47 | 29.5 | 30.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/centernet/centernet_resnet18_dcnv2_140e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/centernet/centernet_resnet18_dcnv2_140e_coco/centernet_resnet18_dcnv2_140e_coco_20210702_155131-c8cd631f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/centernet/centernet_resnet18_dcnv2_140e_coco/centernet_resnet18_dcnv2_140e_coco_20210702_155131.log.json) | + +Note: + +- Flip box AP setting is single-scale and `flip=True`. +- Due to complex data enhancement, we find that the performance is unstable and may fluctuate by about 0.4 mAP. mAP 29.4 ~ 29.8 is acceptable in ResNet-18-DCNv2. +- Compared to the source code, we refer to [CenterNet-Better](https://github.com/FateScript/CenterNet-better), and make the following changes + - fix wrong image mean and variance in image normalization to be compatible with the pre-trained backbone. + - Use SGD rather than ADAM optimizer and add warmup and grad clip. + - Use DistributedDataParallel as other models in MMDetection rather than using DataParallel. diff --git a/configs/centernet/centernet_resnet18_140e_coco.py b/configs/centernet/centernet_resnet18_140e_coco.py new file mode 100644 index 0000000..52c86a5 --- /dev/null +++ b/configs/centernet/centernet_resnet18_140e_coco.py @@ -0,0 +1,3 @@ +_base_ = './centernet_resnet18_dcnv2_140e_coco.py' + +model = dict(neck=dict(use_dcn=False)) diff --git a/configs/centernet/centernet_resnet18_dcnv2_140e_coco.py b/configs/centernet/centernet_resnet18_dcnv2_140e_coco.py new file mode 100644 index 0000000..9eb1db7 --- /dev/null +++ b/configs/centernet/centernet_resnet18_dcnv2_140e_coco.py @@ -0,0 +1,122 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + type='CenterNet', + backbone=dict( + type='ResNet', + depth=18, + norm_eval=False, + norm_cfg=dict(type='BN'), + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet18')), + neck=dict( + type='CTResNetNeck', + in_channel=512, + num_deconv_filters=(256, 128, 64), + num_deconv_kernels=(4, 4, 4), + use_dcn=True), + bbox_head=dict( + type='CenterNetHead', + num_classes=80, + in_channel=64, + feat_channel=64, + loss_center_heatmap=dict(type='GaussianFocalLoss', loss_weight=1.0), + loss_wh=dict(type='L1Loss', loss_weight=0.1), + loss_offset=dict(type='L1Loss', loss_weight=1.0)), + train_cfg=None, + test_cfg=dict(topk=100, local_maximum_kernel=3, max_per_img=100)) + +# We fixed the incorrect img_norm_cfg problem in the source code. +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', to_float32=True, color_type='color'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='RandomCenterCropPad', + crop_size=(512, 512), + ratios=(0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3), + mean=[0, 0, 0], + std=[1, 1, 1], + to_rgb=True, + test_pad_mode=None), + dict(type='Resize', img_scale=(512, 512), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +test_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict( + type='MultiScaleFlipAug', + scale_factor=1.0, + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict( + type='RandomCenterCropPad', + ratios=None, + border=None, + mean=[0, 0, 0], + std=[1, 1, 1], + to_rgb=True, + test_mode=True, + test_pad_mode=['logical_or', 31], + test_pad_add_pix=1), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape', + 'scale_factor', 'flip', 'flip_direction', + 'img_norm_cfg', 'border'), + keys=['img']) + ]) +] + +dataset_type = 'CocoDataset' +data_root = 'data/coco/' + +# Use RepeatDataset to speed up training +data = dict( + samples_per_gpu=16, + workers_per_gpu=4, + train=dict( + _delete_=True, + type='RepeatDataset', + times=5, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) + +# optimizer +# Based on the default settings of modern detectors, the SGD effect is better +# than the Adam in the source code, so we use SGD default settings and +# if you use adam+lr5e-4, the map is 29.1. +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) + +# learning policy +# Based on the default settings of modern detectors, we added warmup settings. +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=1000, + warmup_ratio=1.0 / 1000, + step=[18, 24]) # the real step is [18*5, 24*5] +runner = dict(max_epochs=28) # the real epoch is 28*5=140 diff --git a/configs/centernet/metafile.yml b/configs/centernet/metafile.yml new file mode 100644 index 0000000..e86e57b --- /dev/null +++ b/configs/centernet/metafile.yml @@ -0,0 +1,46 @@ +Collections: + - Name: CenterNet + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x TITANXP GPUs + Architecture: + - ResNet + Paper: + URL: https://arxiv.org/abs/1904.07850 + Title: 'Objects as Points' + README: configs/centernet/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.13.0/mmdet/models/detectors/centernet.py#L10 + Version: v2.13.0 + +Models: + - Name: centernet_resnet18_dcnv2_140e_coco + In Collection: CenterNet + Config: configs/centernet/centernet_resnet18_dcnv2_140e_coco.py + Metadata: + Batch Size: 128 + Training Memory (GB): 3.47 + Epochs: 140 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 29.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/centernet/centernet_resnet18_dcnv2_140e_coco/centernet_resnet18_dcnv2_140e_coco_20210702_155131-c8cd631f.pth + + - Name: centernet_resnet18_140e_coco + In Collection: CenterNet + Config: configs/centernet/centernet_resnet18_140e_coco.py + Metadata: + Batch Size: 128 + Training Memory (GB): 3.45 + Epochs: 140 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 25.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/centernet/centernet_resnet18_140e_coco/centernet_resnet18_140e_coco_20210705_093630-bb5b3bf7.pth diff --git a/configs/centripetalnet/README.md b/configs/centripetalnet/README.md new file mode 100644 index 0000000..543cf06 --- /dev/null +++ b/configs/centripetalnet/README.md @@ -0,0 +1,26 @@ +# CentripetalNet + +## Introduction + + + +```latex +@InProceedings{Dong_2020_CVPR, +author = {Dong, Zhiwei and Li, Guoxuan and Liao, Yue and Wang, Fei and Ren, Pengju and Qian, Chen}, +title = {CentripetalNet: Pursuing High-Quality Keypoint Pairs for Object Detection}, +booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, +month = {June}, +year = {2020} +} +``` + +## Results and models + +| Backbone | Batch Size | Step/Total Epochs | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :--------: |:----------------: | :------: | :------------: | :----: | :------: | :--------: | +| HourglassNet-104 | [16 x 6](./centripetalnet_hourglass104_mstest_16x6_210e_coco.py) | 190/210 | 16.7 | 3.7 | 44.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco/centripetalnet_hourglass104_mstest_16x6_210e_coco_20200915_204804-3ccc61e5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco/centripetalnet_hourglass104_mstest_16x6_210e_coco_20200915_204804.log.json) | + +Note: + +- TTA setting is single-scale and `flip=True`. +- The model we released is the best checkpoint rather than the latest checkpoint (box AP 44.8 vs 44.6 in our experiment). diff --git a/configs/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco.py b/configs/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco.py new file mode 100644 index 0000000..e9c5def --- /dev/null +++ b/configs/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco.py @@ -0,0 +1,105 @@ +_base_ = [ + '../_base_/default_runtime.py', '../_base_/datasets/coco_detection.py' +] + +# model settings +model = dict( + type='CornerNet', + backbone=dict( + type='HourglassNet', + downsample_times=5, + num_stacks=2, + stage_channels=[256, 256, 384, 384, 384, 512], + stage_blocks=[2, 2, 2, 2, 2, 4], + norm_cfg=dict(type='BN', requires_grad=True)), + neck=None, + bbox_head=dict( + type='CentripetalHead', + num_classes=80, + in_channels=256, + num_feat_levels=2, + corner_emb_channels=0, + loss_heatmap=dict( + type='GaussianFocalLoss', alpha=2.0, gamma=4.0, loss_weight=1), + loss_offset=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1), + loss_guiding_shift=dict( + type='SmoothL1Loss', beta=1.0, loss_weight=0.05), + loss_centripetal_shift=dict( + type='SmoothL1Loss', beta=1.0, loss_weight=1)), + # training and testing settings + train_cfg=None, + test_cfg=dict( + corner_topk=100, + local_maximum_kernel=3, + distance_threshold=0.5, + score_thr=0.05, + max_per_img=100, + nms=dict(type='soft_nms', iou_threshold=0.5, method='gaussian'))) +# data settings +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', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='RandomCenterCropPad', + crop_size=(511, 511), + ratios=(0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3), + test_mode=False, + test_pad_mode=None, + **img_norm_cfg), + dict(type='Resize', img_scale=(511, 511), keep_ratio=False), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict( + type='MultiScaleFlipAug', + scale_factor=1.0, + flip=True, + transforms=[ + dict(type='Resize'), + dict( + type='RandomCenterCropPad', + crop_size=None, + ratios=None, + border=None, + test_mode=True, + test_pad_mode=['logical_or', 127], + **img_norm_cfg), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict( + type='Collect', + keys=['img'], + meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape', + 'scale_factor', 'flip', 'img_norm_cfg', 'border')), + ]) +] +data = dict( + samples_per_gpu=6, + workers_per_gpu=3, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='Adam', lr=0.0005) +optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[190]) +runner = dict(type='EpochBasedRunner', max_epochs=210) diff --git a/configs/centripetalnet/metafile.yml b/configs/centripetalnet/metafile.yml new file mode 100644 index 0000000..61aed3e --- /dev/null +++ b/configs/centripetalnet/metafile.yml @@ -0,0 +1,39 @@ +Collections: + - Name: CentripetalNet + Metadata: + Training Data: COCO + Training Techniques: + - Adam + Training Resources: 16x V100 GPUs + Architecture: + - Corner Pooling + - Stacked Hourglass Network + Paper: + URL: https://arxiv.org/abs/2003.09119 + Title: 'CentripetalNet: Pursuing High-quality Keypoint Pairs for Object Detection' + README: configs/centripetalnet/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.5.0/mmdet/models/detectors/cornernet.py#L9 + Version: v2.5.0 + +Models: + - Name: centripetalnet_hourglass104_mstest_16x6_210e_coco + In Collection: CentripetalNet + Config: configs/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco.py + Metadata: + Batch Size: 96 + Training Memory (GB): 16.7 + inference time (ms/im): + - value: 270.27 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 210 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/centripetalnet/centripetalnet_hourglass104_mstest_16x6_210e_coco/centripetalnet_hourglass104_mstest_16x6_210e_coco_20200915_204804-3ccc61e5.pth diff --git a/configs/cityscapes/README.md b/configs/cityscapes/README.md new file mode 100644 index 0000000..b790771 --- /dev/null +++ b/configs/cityscapes/README.md @@ -0,0 +1,33 @@ +# Cityscapes Dataset + + + +``` +@inproceedings{Cordts2016Cityscapes, + title={The Cityscapes Dataset for Semantic Urban Scene Understanding}, + author={Cordts, Marius and Omran, Mohamed and Ramos, Sebastian and Rehfeld, Timo and Enzweiler, Markus and Benenson, Rodrigo and Franke, Uwe and Roth, Stefan and Schiele, Bernt}, + booktitle={Proc. of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + year={2016} +} +``` + +## Common settings + +- All baselines were trained using 8 GPU with a batch size of 8 (1 images per GPU) using the [linear scaling rule](https://arxiv.org/abs/1706.02677) to scale the learning rate. +- All models were trained on `cityscapes_train`, and tested on `cityscapes_val`. +- 1x training schedule indicates 64 epochs which corresponds to slightly less than the 24k iterations reported in the original schedule from the [Mask R-CNN paper](https://arxiv.org/abs/1703.06870) +- COCO pre-trained weights are used to initialize. +- A conversion [script](../../tools/dataset_converters/cityscapes.py) is provided to convert Cityscapes into COCO format. Please refer to [install.md](../../docs/1_exist_data_model.md#prepare-datasets) for details. +- `CityscapesDataset` implemented three evaluation methods. `bbox` and `segm` are standard COCO bbox/mask AP. `cityscapes` is the cityscapes dataset official evaluation, which may be slightly higher than COCO. + +### Faster R-CNN + +| Backbone | Style | Lr schd | Scale | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :---: | :------: | :------------: | :----: | :------: | :--------: | +| R-50-FPN | pytorch | 1x | 800-1024 | 5.2 | - | 40.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes_20200502-829424c0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes_20200502_114915.log.json) | + +### Mask R-CNN + +| Backbone | Style | Lr schd | Scale | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------: | :------------: | :----: | :-----: | :------: | :------: | +| R-50-FPN | pytorch | 1x | 800-1024 | 5.3 | - | 40.9 | 36.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes/mask_rcnn_r50_fpn_1x_cityscapes_20201211_133733-d2858245.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes/mask_rcnn_r50_fpn_1x_cityscapes_20201211_133733.log.json) | diff --git a/configs/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes.py b/configs/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes.py new file mode 100644 index 0000000..c6da80c --- /dev/null +++ b/configs/cityscapes/faster_rcnn_r50_fpn_1x_cityscapes.py @@ -0,0 +1,39 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/cityscapes_detection.py', + '../_base_/default_runtime.py' +] +model = dict( + backbone=dict(init_cfg=None), + roi_head=dict( + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=8, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)))) +# optimizer +# lr is set for a batch size of 8 +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + # [7] yields higher performance than [6] + step=[7]) +runner = dict( + type='EpochBasedRunner', max_epochs=8) # actual epoch = 8 * 8 = 64 +log_config = dict(interval=100) +# For better, more stable performance initialize from COCO +load_from = 'https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth' # noqa diff --git a/configs/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes.py b/configs/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes.py new file mode 100644 index 0000000..679890d --- /dev/null +++ b/configs/cityscapes/mask_rcnn_r50_fpn_1x_cityscapes.py @@ -0,0 +1,46 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/cityscapes_instance.py', '../_base_/default_runtime.py' +] +model = dict( + backbone=dict(init_cfg=None), + roi_head=dict( + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=8, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), + mask_head=dict( + type='FCNMaskHead', + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=8, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0)))) +# optimizer +# lr is set for a batch size of 8 +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + # [7] yields higher performance than [6] + step=[7]) +runner = dict( + type='EpochBasedRunner', max_epochs=8) # actual epoch = 8 * 8 = 64 +log_config = dict(interval=100) +# For better, more stable performance initialize from COCO +load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth' # noqa diff --git a/configs/common/lsj_100e_coco_instance.py b/configs/common/lsj_100e_coco_instance.py new file mode 100644 index 0000000..cacf23d --- /dev/null +++ b/configs/common/lsj_100e_coco_instance.py @@ -0,0 +1,90 @@ +_base_ = '../_base_/default_runtime.py' +# 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) +image_size = (1024, 1024) + +file_client_args = dict(backend='disk') +# comment out the code below to use different file client +# file_client_args = dict( +# backend='petrel', +# path_mapping=dict({ +# './data/': 's3://openmmlab/datasets/detection/', +# 'data/': 's3://openmmlab/datasets/detection/' +# })) + +train_pipeline = [ + dict(type='LoadImageFromFile', file_client_args=file_client_args), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=image_size, + ratio_range=(0.1, 2.0), + multiscale_mode='range', + keep_ratio=True), + dict( + type='RandomCrop', + crop_type='absolute_range', + crop_size=image_size, + recompute_bbox=True, + allow_negative_crop=True), + dict(type='FilterAnnotations', min_gt_bbox_wh=(1e-2, 1e-2)), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size=image_size), # padding to image_size leads 0.5+ mAP + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile', file_client_args=file_client_args), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=4, # simply change this from 2 to 16 for 50e - 400e training. + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=5, metric=['bbox', 'segm']) + +# optimizer assumes bs=64 +optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.00004) +optimizer_config = dict(grad_clip=None) + +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.067, + step=[22, 24]) +runner = dict(type='EpochBasedRunner', max_epochs=25) diff --git a/configs/common/mstrain-poly_3x_coco_instance.py b/configs/common/mstrain-poly_3x_coco_instance.py new file mode 100644 index 0000000..c22ed94 --- /dev/null +++ b/configs/common/mstrain-poly_3x_coco_instance.py @@ -0,0 +1,80 @@ +_base_ = '../_base_/default_runtime.py' +# 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) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', + with_bbox=True, + with_mask=True, + poly2mask=False), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric=['bbox', 'segm']) + +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) + +# learning policy +# Experiments show that using step=[9, 11] has higher performance +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[9, 11]) +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/common/mstrain_3x_coco.py b/configs/common/mstrain_3x_coco.py new file mode 100644 index 0000000..80ec8b8 --- /dev/null +++ b/configs/common/mstrain_3x_coco.py @@ -0,0 +1,76 @@ +_base_ = '../_base_/default_runtime.py' +# 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) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric='bbox') + +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) + +# learning policy +# Experiments show that using step=[9, 11] has higher performance +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[9, 11]) +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/common/mstrain_3x_coco_instance.py b/configs/common/mstrain_3x_coco_instance.py new file mode 100644 index 0000000..50f39be --- /dev/null +++ b/configs/common/mstrain_3x_coco_instance.py @@ -0,0 +1,76 @@ +_base_ = '../_base_/default_runtime.py' +# 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) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric=['bbox', 'segm']) + +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) + +# learning policy +# Experiments show that using step=[9, 11] has higher performance +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[9, 11]) +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/cornernet/README.md b/configs/cornernet/README.md new file mode 100644 index 0000000..a060196 --- /dev/null +++ b/configs/cornernet/README.md @@ -0,0 +1,33 @@ +# CornerNet + +## Introduction + + + +```latex +@inproceedings{law2018cornernet, + title={Cornernet: Detecting objects as paired keypoints}, + author={Law, Hei and Deng, Jia}, + booktitle={15th European Conference on Computer Vision, ECCV 2018}, + pages={765--781}, + year={2018}, + organization={Springer Verlag} +} +``` + +## Results and models + +| Backbone | Batch Size | Step/Total Epochs | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :--------: |:----------------: | :------: | :------------: | :----: | :------: | :--------: | +| HourglassNet-104 | [10 x 5](./cornernet_hourglass104_mstest_10x5_210e_coco.py) | 180/210 | 13.9 | 4.2 | 41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco/cornernet_hourglass104_mstest_10x5_210e_coco_20200824_185720-5fefbf1c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco/cornernet_hourglass104_mstest_10x5_210e_coco_20200824_185720.log.json) | +| HourglassNet-104 | [8 x 6](./cornernet_hourglass104_mstest_8x6_210e_coco.py) | 180/210 | 15.9 | 4.2 | 41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco/cornernet_hourglass104_mstest_8x6_210e_coco_20200825_150618-79b44c30.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco/cornernet_hourglass104_mstest_8x6_210e_coco_20200825_150618.log.json) | +| HourglassNet-104 | [32 x 3](./cornernet_hourglass104_mstest_32x3_210e_coco.py) | 180/210 | 9.5 | 3.9 | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco/cornernet_hourglass104_mstest_32x3_210e_coco_20200819_203110-1efaea91.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco/cornernet_hourglass104_mstest_32x3_210e_coco_20200819_203110.log.json) | + +Note: + +- TTA setting is single-scale and `flip=True`. +- Experiments with `images_per_gpu=6` are conducted on Tesla V100-SXM2-32GB, `images_per_gpu=3` are conducted on GeForce GTX 1080 Ti. +- Here are the descriptions of each experiment setting: + - 10 x 5: 10 GPUs with 5 images per gpu. This is the same setting as that reported in the original paper. + - 8 x 6: 8 GPUs with 6 images per gpu. The total batchsize is similar to paper and only need 1 node to train. + - 32 x 3: 32 GPUs with 3 images per gpu. The default setting for 1080TI and need 4 nodes to train. diff --git a/configs/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco.py b/configs/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco.py new file mode 100644 index 0000000..89f3876 --- /dev/null +++ b/configs/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco.py @@ -0,0 +1,105 @@ +_base_ = [ + '../_base_/default_runtime.py', '../_base_/datasets/coco_detection.py' +] + +# model settings +model = dict( + type='CornerNet', + backbone=dict( + type='HourglassNet', + downsample_times=5, + num_stacks=2, + stage_channels=[256, 256, 384, 384, 384, 512], + stage_blocks=[2, 2, 2, 2, 2, 4], + norm_cfg=dict(type='BN', requires_grad=True)), + neck=None, + bbox_head=dict( + type='CornerHead', + num_classes=80, + in_channels=256, + num_feat_levels=2, + corner_emb_channels=1, + loss_heatmap=dict( + type='GaussianFocalLoss', alpha=2.0, gamma=4.0, loss_weight=1), + loss_embedding=dict( + type='AssociativeEmbeddingLoss', + pull_weight=0.10, + push_weight=0.10), + loss_offset=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1)), + # training and testing settings + train_cfg=None, + test_cfg=dict( + corner_topk=100, + local_maximum_kernel=3, + distance_threshold=0.5, + score_thr=0.05, + max_per_img=100, + nms=dict(type='soft_nms', iou_threshold=0.5, method='gaussian'))) +# data settings +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', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='RandomCenterCropPad', + crop_size=(511, 511), + ratios=(0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3), + test_mode=False, + test_pad_mode=None, + **img_norm_cfg), + dict(type='Resize', img_scale=(511, 511), keep_ratio=False), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict( + type='MultiScaleFlipAug', + scale_factor=1.0, + flip=True, + transforms=[ + dict(type='Resize'), + dict( + type='RandomCenterCropPad', + crop_size=None, + ratios=None, + border=None, + test_mode=True, + test_pad_mode=['logical_or', 127], + **img_norm_cfg), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict( + type='Collect', + keys=['img'], + meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape', + 'scale_factor', 'flip', 'img_norm_cfg', 'border')), + ]) +] +data = dict( + samples_per_gpu=5, + workers_per_gpu=3, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='Adam', lr=0.0005) +optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[180]) +runner = dict(type='EpochBasedRunner', max_epochs=210) diff --git a/configs/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco.py b/configs/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco.py new file mode 100644 index 0000000..873d598 --- /dev/null +++ b/configs/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco.py @@ -0,0 +1,105 @@ +_base_ = [ + '../_base_/default_runtime.py', '../_base_/datasets/coco_detection.py' +] + +# model settings +model = dict( + type='CornerNet', + backbone=dict( + type='HourglassNet', + downsample_times=5, + num_stacks=2, + stage_channels=[256, 256, 384, 384, 384, 512], + stage_blocks=[2, 2, 2, 2, 2, 4], + norm_cfg=dict(type='BN', requires_grad=True)), + neck=None, + bbox_head=dict( + type='CornerHead', + num_classes=80, + in_channels=256, + num_feat_levels=2, + corner_emb_channels=1, + loss_heatmap=dict( + type='GaussianFocalLoss', alpha=2.0, gamma=4.0, loss_weight=1), + loss_embedding=dict( + type='AssociativeEmbeddingLoss', + pull_weight=0.10, + push_weight=0.10), + loss_offset=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1)), + # training and testing settings + train_cfg=None, + test_cfg=dict( + corner_topk=100, + local_maximum_kernel=3, + distance_threshold=0.5, + score_thr=0.05, + max_per_img=100, + nms=dict(type='soft_nms', iou_threshold=0.5, method='gaussian'))) +# data settings +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', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='RandomCenterCropPad', + crop_size=(511, 511), + ratios=(0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3), + test_mode=False, + test_pad_mode=None, + **img_norm_cfg), + dict(type='Resize', img_scale=(511, 511), keep_ratio=False), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict( + type='MultiScaleFlipAug', + scale_factor=1.0, + flip=True, + transforms=[ + dict(type='Resize'), + dict( + type='RandomCenterCropPad', + crop_size=None, + ratios=None, + border=None, + test_mode=True, + test_pad_mode=['logical_or', 127], + **img_norm_cfg), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict( + type='Collect', + keys=['img'], + meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape', + 'scale_factor', 'flip', 'img_norm_cfg', 'border')), + ]) +] +data = dict( + samples_per_gpu=3, + workers_per_gpu=3, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='Adam', lr=0.0005) +optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[180]) +runner = dict(type='EpochBasedRunner', max_epochs=210) diff --git a/configs/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco.py b/configs/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco.py new file mode 100644 index 0000000..ef749cc --- /dev/null +++ b/configs/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco.py @@ -0,0 +1,105 @@ +_base_ = [ + '../_base_/default_runtime.py', '../_base_/datasets/coco_detection.py' +] + +# model settings +model = dict( + type='CornerNet', + backbone=dict( + type='HourglassNet', + downsample_times=5, + num_stacks=2, + stage_channels=[256, 256, 384, 384, 384, 512], + stage_blocks=[2, 2, 2, 2, 2, 4], + norm_cfg=dict(type='BN', requires_grad=True)), + neck=None, + bbox_head=dict( + type='CornerHead', + num_classes=80, + in_channels=256, + num_feat_levels=2, + corner_emb_channels=1, + loss_heatmap=dict( + type='GaussianFocalLoss', alpha=2.0, gamma=4.0, loss_weight=1), + loss_embedding=dict( + type='AssociativeEmbeddingLoss', + pull_weight=0.10, + push_weight=0.10), + loss_offset=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1)), + # training and testing settings + train_cfg=None, + test_cfg=dict( + corner_topk=100, + local_maximum_kernel=3, + distance_threshold=0.5, + score_thr=0.05, + max_per_img=100, + nms=dict(type='soft_nms', iou_threshold=0.5, method='gaussian'))) +# data settings +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', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='RandomCenterCropPad', + crop_size=(511, 511), + ratios=(0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3), + test_mode=False, + test_pad_mode=None, + **img_norm_cfg), + dict(type='Resize', img_scale=(511, 511), keep_ratio=False), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict( + type='MultiScaleFlipAug', + scale_factor=1.0, + flip=True, + transforms=[ + dict(type='Resize'), + dict( + type='RandomCenterCropPad', + crop_size=None, + ratios=None, + border=None, + test_mode=True, + test_pad_mode=['logical_or', 127], + **img_norm_cfg), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict( + type='Collect', + keys=['img'], + meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape', + 'scale_factor', 'flip', 'img_norm_cfg', 'border')), + ]) +] +data = dict( + samples_per_gpu=6, + workers_per_gpu=3, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='Adam', lr=0.0005) +optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[180]) +runner = dict(type='EpochBasedRunner', max_epochs=210) diff --git a/configs/cornernet/metafile.yml b/configs/cornernet/metafile.yml new file mode 100644 index 0000000..c2f6143 --- /dev/null +++ b/configs/cornernet/metafile.yml @@ -0,0 +1,83 @@ +Collections: + - Name: CornerNet + Metadata: + Training Data: COCO + Training Techniques: + - Adam + Training Resources: 8x V100 GPUs + Architecture: + - Corner Pooling + - Stacked Hourglass Network + Paper: + URL: https://arxiv.org/abs/1808.01244 + Title: 'CornerNet: Detecting Objects as Paired Keypoints' + README: configs/cornernet/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.3.0/mmdet/models/detectors/cornernet.py#L9 + Version: v2.3.0 + +Models: + - Name: cornernet_hourglass104_mstest_10x5_210e_coco + In Collection: CornerNet + Config: configs/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco.py + Metadata: + Training Resources: 10x V100 GPUs + Batch Size: 50 + Training Memory (GB): 13.9 + inference time (ms/im): + - value: 238.1 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 210 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_10x5_210e_coco/cornernet_hourglass104_mstest_10x5_210e_coco_20200824_185720-5fefbf1c.pth + + - Name: cornernet_hourglass104_mstest_8x6_210e_coco + In Collection: CornerNet + Config: configs/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco.py + Metadata: + Batch Size: 48 + Training Memory (GB): 15.9 + inference time (ms/im): + - value: 238.1 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 210 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_8x6_210e_coco/cornernet_hourglass104_mstest_8x6_210e_coco_20200825_150618-79b44c30.pth + + - Name: cornernet_hourglass104_mstest_32x3_210e_coco + In Collection: CornerNet + Config: configs/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco.py + Metadata: + Training Resources: 32x V100 GPUs + Batch Size: 96 + Training Memory (GB): 9.5 + inference time (ms/im): + - value: 256.41 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 210 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/cornernet/cornernet_hourglass104_mstest_32x3_210e_coco/cornernet_hourglass104_mstest_32x3_210e_coco_20200819_203110-1efaea91.pth diff --git a/configs/dcn/README.md b/configs/dcn/README.md new file mode 100644 index 0000000..044ff29 --- /dev/null +++ b/configs/dcn/README.md @@ -0,0 +1,52 @@ +# Deformable Convolutional Networks + +## Introduction + + + +```none +@inproceedings{dai2017deformable, + title={Deformable Convolutional Networks}, + author={Dai, Jifeng and Qi, Haozhi and Xiong, Yuwen and Li, Yi and Zhang, Guodong and Hu, Han and Wei, Yichen}, + booktitle={Proceedings of the IEEE international conference on computer vision}, + year={2017} +} +``` + + + +``` +@article{zhu2018deformable, + title={Deformable ConvNets v2: More Deformable, Better Results}, + author={Zhu, Xizhou and Hu, Han and Lin, Stephen and Dai, Jifeng}, + journal={arXiv preprint arXiv:1811.11168}, + year={2018} +} +``` + +## Results and Models + +| Backbone | Model | Style | Conv | Pool | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:----------------:|:------------:|:-------:|:-------------:|:------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN | Faster | pytorch | dconv(c3-c5) | - | 1x | 4.0 | 17.8 | 41.3 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130-d68aed1e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130_212941.log.json) | +| R-50-FPN | Faster | pytorch | mdconv(c3-c5) | - | 1x | 4.1 | 17.6 | 41.4 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco_20200130-d099253b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco_20200130_222144.log.json) | +| *R-50-FPN (dg=4) | Faster | pytorch | mdconv(c3-c5) | - | 1x | 4.2 | 17.4 | 41.5 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco_20200130-01262257.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco_20200130_222058.log.json) | +| R-50-FPN | Faster | pytorch | - | dpool | 1x | 5.0 | 17.2 | 38.9 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_dpool_1x_coco/faster_rcnn_r50_fpn_dpool_1x_coco_20200307-90d3c01d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_dpool_1x_coco/faster_rcnn_r50_fpn_dpool_1x_coco_20200307_203250.log.json) | +| R-50-FPN | Faster | pytorch | - | mdpool | 1x | 5.8 | 16.6 | 38.7 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco/faster_rcnn_r50_fpn_mdpool_1x_coco_20200307-c0df27ff.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco/faster_rcnn_r50_fpn_mdpool_1x_coco_20200307_203304.log.json) | +| R-101-FPN | Faster | pytorch | dconv(c3-c5) | - | 1x | 6.0 | 12.5 | 42.7 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-1377f13d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203_230019.log.json) | +| X-101-32x4d-FPN | Faster | pytorch | dconv(c3-c5) | - | 1x | 7.3 | 10.0 | 44.5 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco_20200203-4f85c69c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco_20200203_001325.log.json) | +| R-50-FPN | Mask | pytorch | dconv(c3-c5) | - | 1x | 4.5 | 15.4 | 41.8 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200203-4d9ad43b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200203_061339.log.json) | +| R-50-FPN | Mask | pytorch | mdconv(c3-c5) | - | 1x | 4.5 | 15.1 | 41.5 | 37.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco_20200203-ad97591f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco_20200203_063443.log.json) | +| R-101-FPN | Mask | pytorch | dconv(c3-c5) | - | 1x | 6.5 | 11.7 | 43.5 | 38.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200216-a71f5bce.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200216_191601.log.json) | +| R-50-FPN | Cascade | pytorch | dconv(c3-c5) | - | 1x | 4.5 | 14.6 | 43.8 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130-2f1fca44.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130_220843.log.json) | +| R-101-FPN | Cascade | pytorch | dconv(c3-c5) | - | 1x | 6.4 | 11.0 | 45.0 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203_224829.log.json) | +| R-50-FPN | Cascade Mask | pytorch | dconv(c3-c5) | - | 1x | 6.0 | 10.0 | 44.4 | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200202-42e767a2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200202_010309.log.json) | +| R-101-FPN | Cascade Mask | pytorch | dconv(c3-c5) | - | 1x | 8.0 | 8.6 | 45.8 | 39.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200204-df0c5f10.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200204_134006.log.json) | +| X-101-32x4d-FPN | Cascade Mask | pytorch | dconv(c3-c5) | - | 1x | 9.2 | | 47.3 | 41.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco-e75f90c8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco-20200606_183737.log.json) | + +**Notes:** + +- `dconv` and `mdconv` denote (modulated) deformable convolution, `c3-c5` means adding dconv in resnet stage 3 to 5. `dpool` and `mdpool` denote (modulated) deformable roi pooling. +- The dcn ops are modified from https://github.com/chengdazhi/Deformable-Convolution-V2-PyTorch, which should be more memory efficient and slightly faster. +- (*) For R-50-FPN (dg=4), dg is short for deformable_group. This model is trained and tested on Amazon EC2 p3dn.24xlarge instance. +- **Memory, Train/Inf time is outdated.** diff --git a/configs/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..081b998 --- /dev/null +++ b/configs/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..3b3683a --- /dev/null +++ b/configs/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..daaa472 --- /dev/null +++ b/configs/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..a01df33 --- /dev/null +++ b/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../cascade_rcnn/cascade_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..aa664bd --- /dev/null +++ b/configs/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..f5fee7e --- /dev/null +++ b/configs/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..8787088 --- /dev/null +++ b/configs/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py b/configs/dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py new file mode 100644 index 0000000..1b695f0 --- /dev/null +++ b/configs/dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py @@ -0,0 +1,12 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + _delete_=True, + type='DeformRoIPoolPack', + output_size=7, + output_channels=256), + out_channels=256, + featmap_strides=[4, 8, 16, 32]))) diff --git a/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py b/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..d1bcf3c --- /dev/null +++ b/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCNv2', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py b/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py new file mode 100644 index 0000000..d0ab89c --- /dev/null +++ b/configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCNv2', deform_groups=4, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py b/configs/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py new file mode 100644 index 0000000..ad7b034 --- /dev/null +++ b/configs/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py @@ -0,0 +1,12 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + _delete_=True, + type='ModulatedDeformRoIPoolPack', + output_size=7, + output_channels=256), + out_channels=256, + featmap_strides=[4, 8, 16, 32]))) diff --git a/configs/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..e3bea19 --- /dev/null +++ b/configs/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..cb34002 --- /dev/null +++ b/configs/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py b/configs/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..ababe58 --- /dev/null +++ b/configs/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py b/configs/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..5ca2a67 --- /dev/null +++ b/configs/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCNv2', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/dcn/metafile.yml b/configs/dcn/metafile.yml new file mode 100644 index 0000000..4fcbce6 --- /dev/null +++ b/configs/dcn/metafile.yml @@ -0,0 +1,335 @@ +Collections: + - Name: Deformable Convolutional Networks + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Deformable Convolution + Paper: + URL: https://arxiv.org/abs/1811.11168 + Title: 'Deformable ConvNets v2: More Deformable, Better Results' + README: configs/dcn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/ops/dcn/deform_conv.py#L15 + Version: v2.0.0 + +Models: + - Name: faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 4.0 + inference time (ms/im): + - value: 56.18 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco/faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130-d68aed1e.pth + + - Name: faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 4.1 + inference time (ms/im): + - value: 56.82 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco/faster_rcnn_r50_fpn_mdconv_c3-c5_1x_coco_20200130-d099253b.pth + + - Name: faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco.py + Metadata: + Training Memory (GB): 4.2 + inference time (ms/im): + - value: 57.47 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco/faster_rcnn_r50_fpn_mdconv_c3-c5_group4_1x_coco_20200130-01262257.pth + + - Name: faster_rcnn_r50_fpn_dpool_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_r50_fpn_dpool_1x_coco.py + Metadata: + Training Memory (GB): 5.0 + inference time (ms/im): + - value: 58.14 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_dpool_1x_coco/faster_rcnn_r50_fpn_dpool_1x_coco_20200307-90d3c01d.pth + + - Name: faster_rcnn_r50_fpn_mdpool_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco.py + Metadata: + Training Memory (GB): 5.8 + inference time (ms/im): + - value: 60.24 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r50_fpn_mdpool_1x_coco/faster_rcnn_r50_fpn_mdpool_1x_coco_20200307-c0df27ff.pth + + - Name: faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 80 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco/faster_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-1377f13d.pth + + - Name: faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 7.3 + inference time (ms/im): + - value: 100 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco/faster_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco_20200203-4f85c69c.pth + + - Name: mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 4.5 + inference time (ms/im): + - value: 64.94 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200203-4d9ad43b.pth + + - Name: mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 4.5 + inference time (ms/im): + - value: 66.23 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_mdconv_c3-c5_1x_coco_20200203-ad97591f.pth + + - Name: mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 6.5 + inference time (ms/im): + - value: 85.47 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco/mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200216-a71f5bce.pth + + - Name: cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 4.5 + inference time (ms/im): + - value: 68.49 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco/cascade_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130-2f1fca44.pth + + - Name: cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 6.4 + inference time (ms/im): + - value: 90.91 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth + + - Name: cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 100 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200202-42e767a2.pth + + - Name: cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 8.0 + inference time (ms/im): + - value: 116.28 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200204-df0c5f10.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco + In Collection: Deformable Convolutional Networks + Config: configs/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 9.2 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 41.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco-e75f90c8.pth diff --git a/configs/deepfashion/README.md b/configs/deepfashion/README.md new file mode 100644 index 0000000..e21cce3 --- /dev/null +++ b/configs/deepfashion/README.md @@ -0,0 +1,56 @@ +# DeepFashion + + + +[MMFashion](https://github.com/open-mmlab/mmfashion) develops "fashion parsing and segmentation" module +based on the dataset +[DeepFashion-Inshop](https://drive.google.com/drive/folders/0B7EVK8r0v71pVDZFQXRsMDZCX1E?usp=sharing). +Its annotation follows COCO style. +To use it, you need to first download the data. Note that we only use "img_highres" in this task. +The file tree should be like this: + +```sh +mmdetection +├── mmdet +├── tools +├── configs +├── data +│ ├── DeepFashion +│ │ ├── In-shop +│ │ ├── Anno +│ │ │   ├── segmentation +│ │ │   | ├── DeepFashion_segmentation_train.json +│ │ │   | ├── DeepFashion_segmentation_query.json +│ │ │   | ├── DeepFashion_segmentation_gallery.json +│ │ │   ├── list_bbox_inshop.txt +│ │ │   ├── list_description_inshop.json +│ │ │   ├── list_item_inshop.txt +│ │ │   └── list_landmarks_inshop.txt +│ │ ├── Eval +│ │ │ └── list_eval_partition.txt +│ │ ├── Img +│ │ │ ├── img +│ │ │ │ ├──XXX.jpg +│ │ │ ├── img_highres +│ │ │ └── ├──XXX.jpg + +``` + +After that you can train the Mask RCNN r50 on DeepFashion-In-shop dataset by launching training with the `mask_rcnn_r50_fpn_1x.py` config +or creating your own config file. + +``` +@inproceedings{liuLQWTcvpr16DeepFashion, + author = {Liu, Ziwei and Luo, Ping and Qiu, Shi and Wang, Xiaogang and Tang, Xiaoou}, + title = {DeepFashion: Powering Robust Clothes Recognition and Retrieval with Rich Annotations}, + booktitle = {Proceedings of IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2016} +} +``` + +## Model Zoo + +| Backbone | Model type | Dataset | bbox detection Average Precision | segmentation Average Precision | Config | Download (Google) | +| :---------: | :----------: | :-----------------: | :--------------------------------: | :----------------------------: | :---------:| :-------------------------: | +| ResNet50 | Mask RCNN | DeepFashion-In-shop | 0.599 | 0.584 |[config](https://github.com/open-mmlab/mmdetection/blob/master/configs/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion.py)| [model](https://download.openmmlab.com/mmdetection/v2.0/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion/mask_rcnn_r50_fpn_15e_deepfashion_20200329_192752.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion/20200329_192752.log.json) | diff --git a/configs/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion.py b/configs/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion.py new file mode 100644 index 0000000..c4e8638 --- /dev/null +++ b/configs/deepfashion/mask_rcnn_r50_fpn_15e_deepfashion.py @@ -0,0 +1,10 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/deepfashion.py', '../_base_/schedules/schedule_1x.py', + '../_base_/default_runtime.py' +] +model = dict( + roi_head=dict( + bbox_head=dict(num_classes=15), mask_head=dict(num_classes=15))) +# runtime settings +runner = dict(type='EpochBasedRunner', max_epochs=15) diff --git a/configs/deformable_detr/README.md b/configs/deformable_detr/README.md new file mode 100644 index 0000000..fe68002 --- /dev/null +++ b/configs/deformable_detr/README.md @@ -0,0 +1,31 @@ +# Deformable DETR + +## Introduction + + + +We provide the config files for Deformable DETR: [Deformable DETR: Deformable Transformers for End-to-End Object Detection](https://arxiv.org/abs/2010.04159). + +``` +@inproceedings{ +zhu2021deformable, +title={Deformable DETR: Deformable Transformers for End-to-End Object Detection}, +author={Xizhou Zhu and Weijie Su and Lewei Lu and Bin Li and Xiaogang Wang and Jifeng Dai}, +booktitle={International Conference on Learning Representations}, +year={2021}, +url={https://openreview.net/forum?id=gZ9hCDWe6ke} +} +``` + +## Results and Models + +| Backbone | Model | Lr schd | box AP | Config | Download | +|:------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | Deformable DETR |50e | 44.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/deformable_detr/deformable_detr_r50_16x2_50e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_r50_16x2_50e_coco/deformable_detr_r50_16x2_50e_coco_20210419_220030-a12b9512.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_r50_16x2_50e_coco/deformable_detr_r50_16x2_50e_coco_20210419_220030-a12b9512.log.json) | +| R-50 | + iterative bounding box refinement |50e | 46.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco/deformable_detr_refine_r50_16x2_50e_coco_20210419_220503-5f5dff21.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco/deformable_detr_refine_r50_16x2_50e_coco_20210419_220503-5f5dff21.log.json) | +| R-50 | ++ two-stage Deformable DETR |50e | 46.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco/deformable_detr_twostage_refine_r50_16x2_50e_coco_20210419_220613-9d28ab72.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco/deformable_detr_twostage_refine_r50_16x2_50e_coco_20210419_220613-9d28ab72.log.json) | + +# NOTE + +1. All models are trained with batch size 32. +2. The performance is unstable. `Deformable DETR` and `iterative bounding box refinement` may fluctuate about 0.3 mAP. `two-stage Deformable DETR` may fluctuate about 0.2 mAP. diff --git a/configs/deformable_detr/deformable_detr_r50_16x2_50e_coco.py b/configs/deformable_detr/deformable_detr_r50_16x2_50e_coco.py new file mode 100644 index 0000000..0a58d9a --- /dev/null +++ b/configs/deformable_detr/deformable_detr_r50_16x2_50e_coco.py @@ -0,0 +1,172 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', '../_base_/default_runtime.py' +] +model = dict( + type='DeformableDETR', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='ChannelMapper', + in_channels=[512, 1024, 2048], + kernel_size=1, + out_channels=256, + act_cfg=None, + norm_cfg=dict(type='GN', num_groups=32), + num_outs=4), + bbox_head=dict( + type='DeformableDETRHead', + num_query=300, + num_classes=80, + in_channels=2048, + sync_cls_avg_factor=True, + as_two_stage=False, + transformer=dict( + type='DeformableDetrTransformer', + encoder=dict( + type='DetrTransformerEncoder', + num_layers=6, + transformerlayers=dict( + type='BaseTransformerLayer', + attn_cfgs=dict( + type='MultiScaleDeformableAttention', embed_dims=256), + feedforward_channels=1024, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'ffn', 'norm'))), + decoder=dict( + type='DeformableDetrTransformerDecoder', + num_layers=6, + return_intermediate=True, + transformerlayers=dict( + type='DetrTransformerDecoderLayer', + attn_cfgs=[ + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1), + dict( + type='MultiScaleDeformableAttention', + embed_dims=256) + ], + feedforward_channels=1024, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'cross_attn', 'norm', + 'ffn', 'norm')))), + positional_encoding=dict( + type='SinePositionalEncoding', + num_feats=128, + normalize=True, + offset=-0.5), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=2.0), + loss_bbox=dict(type='L1Loss', loss_weight=5.0), + loss_iou=dict(type='GIoULoss', loss_weight=2.0)), + # training and testing settings + train_cfg=dict( + assigner=dict( + type='HungarianAssigner', + cls_cost=dict(type='FocalLossCost', weight=2.0), + reg_cost=dict(type='BBoxL1Cost', weight=5.0, box_format='xywh'), + iou_cost=dict(type='IoUCost', iou_mode='giou', weight=2.0))), + test_cfg=dict(max_per_img=100)) +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +# train_pipeline, NOTE the img_scale and the Pad's size_divisor is different +# from the default setting in mmdet. +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='AutoAugment', + policies=[ + [ + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), + (576, 1333), (608, 1333), (640, 1333), + (672, 1333), (704, 1333), (736, 1333), + (768, 1333), (800, 1333)], + multiscale_mode='value', + keep_ratio=True) + ], + [ + dict( + type='Resize', + # The radio of all image in train dataset < 7 + # follow the original impl + img_scale=[(400, 4200), (500, 4200), (600, 4200)], + multiscale_mode='value', + keep_ratio=True), + dict( + type='RandomCrop', + crop_type='absolute_range', + crop_size=(384, 600), + allow_negative_crop=True), + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), + (576, 1333), (608, 1333), (640, 1333), + (672, 1333), (704, 1333), (736, 1333), + (768, 1333), (800, 1333)], + multiscale_mode='value', + override=True, + keep_ratio=True) + ] + ]), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict(filter_empty_gt=False, pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='AdamW', + lr=2e-4, + weight_decay=0.0001, + paramwise_cfg=dict( + custom_keys={ + 'backbone': dict(lr_mult=0.1), + 'sampling_offsets': dict(lr_mult=0.1), + 'reference_points': dict(lr_mult=0.1) + })) +optimizer_config = dict(grad_clip=dict(max_norm=0.1, norm_type=2)) +# learning policy +lr_config = dict(policy='step', step=[40]) +runner = dict(type='EpochBasedRunner', max_epochs=50) diff --git a/configs/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco.py b/configs/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco.py new file mode 100644 index 0000000..01f13df --- /dev/null +++ b/configs/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco.py @@ -0,0 +1,2 @@ +_base_ = 'deformable_detr_r50_16x2_50e_coco.py' +model = dict(bbox_head=dict(with_box_refine=True)) diff --git a/configs/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco.py b/configs/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco.py new file mode 100644 index 0000000..2aa840d --- /dev/null +++ b/configs/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco.py @@ -0,0 +1,2 @@ +_base_ = 'deformable_detr_refine_r50_16x2_50e_coco.py' +model = dict(bbox_head=dict(as_two_stage=True)) diff --git a/configs/deformable_detr/metafile.yml b/configs/deformable_detr/metafile.yml new file mode 100644 index 0000000..873292d --- /dev/null +++ b/configs/deformable_detr/metafile.yml @@ -0,0 +1,56 @@ +Collections: + - Name: Deformable DETR + Metadata: + Training Data: COCO + Training Techniques: + - AdamW + - Multi Scale Train + - Gradient Clip + Training Resources: 8x V100 GPUs + Architecture: + - ResNet + - Transformer + Paper: + URL: https://openreview.net/forum?id=gZ9hCDWe6ke + Title: 'Deformable DETR: Deformable Transformers for End-to-End Object Detection' + README: configs/deformable_detr/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.12.0/mmdet/models/detectors/deformable_detr.py#L6 + Version: v2.12.0 + +Models: + - Name: deformable_detr_r50_16x2_50e_coco + In Collection: Deformable DETR + Config: configs/deformable_detr/deformable_detr_r50_16x2_50e_coco.py + Metadata: + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_r50_16x2_50e_coco/deformable_detr_r50_16x2_50e_coco_20210419_220030-a12b9512.pth + + - Name: deformable_detr_refine_r50_16x2_50e_coco + In Collection: Deformable DETR + Config: configs/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco.py + Metadata: + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_refine_r50_16x2_50e_coco/deformable_detr_refine_r50_16x2_50e_coco_20210419_220503-5f5dff21.pth + + - Name: deformable_detr_twostage_refine_r50_16x2_50e_coco + In Collection: Deformable DETR + Config: configs/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco.py + Metadata: + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/deformable_detr/deformable_detr_twostage_refine_r50_16x2_50e_coco/deformable_detr_twostage_refine_r50_16x2_50e_coco_20210419_220613-9d28ab72.pth diff --git a/configs/detectors/README.md b/configs/detectors/README.md new file mode 100644 index 0000000..37c151f --- /dev/null +++ b/configs/detectors/README.md @@ -0,0 +1,59 @@ +# DetectoRS + +## Introduction + + + +We provide the config files for [DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolution](https://arxiv.org/pdf/2006.02334.pdf). + +```BibTeX +@article{qiao2020detectors, + title={DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolution}, + author={Qiao, Siyuan and Chen, Liang-Chieh and Yuille, Alan}, + journal={arXiv preprint arXiv:2006.02334}, + year={2020} +} +``` + +## Dataset + +DetectoRS requires COCO and [COCO-stuff](http://calvin.inf.ed.ac.uk/wp-content/uploads/data/cocostuffdataset/stuffthingmaps_trainval2017.zip) dataset for training. You need to download and extract it in the COCO dataset path. +The directory should be like this. + +```none +mmdetection +├── mmdet +├── tools +├── configs +├── data +│ ├── coco +│ │ ├── annotations +│ │ ├── train2017 +│ │ ├── val2017 +│ │ ├── test2017 +| | ├── stuffthingmaps +``` + +## Results and Models + +DetectoRS includes two major components: + +- Recursive Feature Pyramid (RFP). +- Switchable Atrous Convolution (SAC). + +They can be used independently. +Combining them together results in DetectoRS. +The results on COCO 2017 val are shown in the below table. + +| Method | Detector | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:------:|:--------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| RFP | Cascade + ResNet-50 | 1x | 7.5 | - | 44.8 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/cascade_rcnn_r50_rfp_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/cascade_rcnn_r50_rfp_1x_coco/cascade_rcnn_r50_rfp_1x_coco-8cf51bfd.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/cascade_rcnn_r50_rfp_1x_coco/cascade_rcnn_r50_rfp_1x_coco_20200624_104126.log.json) | +| SAC | Cascade + ResNet-50 | 1x | 5.6 | - | 45.0| | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/cascade_rcnn_r50_sac_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/cascade_rcnn_r50_sac_1x_coco/cascade_rcnn_r50_sac_1x_coco-24bfda62.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/cascade_rcnn_r50_sac_1x_coco/cascade_rcnn_r50_sac_1x_coco_20200624_104402.log.json) | +| DetectoRS | Cascade + ResNet-50 | 1x | 9.9 | - | 47.4 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_cascade_rcnn_r50_1x_coco/detectors_cascade_rcnn_r50_1x_coco-32a10ba0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_cascade_rcnn_r50_1x_coco/detectors_cascade_rcnn_r50_1x_coco_20200706_001203.log.json) | +| RFP | HTC + ResNet-50 | 1x | 11.2 | - | 46.6 | 40.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/htc_r50_rfp_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/htc_r50_rfp_1x_coco/htc_r50_rfp_1x_coco-8ff87c51.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/htc_r50_rfp_1x_coco/htc_r50_rfp_1x_coco_20200624_103053.log.json) | +| SAC | HTC + ResNet-50 | 1x | 9.3 | - | 46.4 | 40.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/htc_r50_sac_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/htc_r50_sac_1x_coco/htc_r50_sac_1x_coco-bfa60c54.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/htc_r50_sac_1x_coco/htc_r50_sac_1x_coco_20200624_103111.log.json) | +| DetectoRS | HTC + ResNet-50 | 1x | 13.6 | - | 49.1 | 42.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/detectors_htc_r50_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_htc_r50_1x_coco/detectors_htc_r50_1x_coco-329b1453.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_htc_r50_1x_coco/detectors_htc_r50_1x_coco_20200624_103659.log.json) | +| DetectoRS | HTC + ResNet-101 | 20e | 19.6 | | 50.5 | 43.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detectors/detectors_htc_r101_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_htc_r101_20e_coco/detectors_htc_r101_20e_coco_20210419_203638-348d533b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_htc_r101_20e_coco/detectors_htc_r101_20e_coco_20210419_203638.log.json) | + +*Note*: This is a re-implementation based on MMDetection-V2. +The original implementation is based on MMDetection-V1. diff --git a/configs/detectors/cascade_rcnn_r50_rfp_1x_coco.py b/configs/detectors/cascade_rcnn_r50_rfp_1x_coco.py new file mode 100644 index 0000000..4430d8a --- /dev/null +++ b/configs/detectors/cascade_rcnn_r50_rfp_1x_coco.py @@ -0,0 +1,28 @@ +_base_ = [ + '../_base_/models/cascade_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + output_img=True), + neck=dict( + type='RFP', + rfp_steps=2, + aspp_out_channels=64, + aspp_dilations=(1, 3, 6, 1), + rfp_backbone=dict( + rfp_inplanes=256, + type='DetectoRS_ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + conv_cfg=dict(type='ConvAWS'), + pretrained='torchvision://resnet50', + style='pytorch'))) diff --git a/configs/detectors/cascade_rcnn_r50_sac_1x_coco.py b/configs/detectors/cascade_rcnn_r50_sac_1x_coco.py new file mode 100644 index 0000000..ccd9319 --- /dev/null +++ b/configs/detectors/cascade_rcnn_r50_sac_1x_coco.py @@ -0,0 +1,12 @@ +_base_ = [ + '../_base_/models/cascade_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True))) diff --git a/configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py b/configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py new file mode 100644 index 0000000..f760404 --- /dev/null +++ b/configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py @@ -0,0 +1,32 @@ +_base_ = [ + '../_base_/models/cascade_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True), + output_img=True), + neck=dict( + type='RFP', + rfp_steps=2, + aspp_out_channels=64, + aspp_dilations=(1, 3, 6, 1), + rfp_backbone=dict( + rfp_inplanes=256, + type='DetectoRS_ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True), + pretrained='torchvision://resnet50', + style='pytorch'))) diff --git a/configs/detectors/detectors_htc_r101_20e_coco.py b/configs/detectors/detectors_htc_r101_20e_coco.py new file mode 100644 index 0000000..93d7d2b --- /dev/null +++ b/configs/detectors/detectors_htc_r101_20e_coco.py @@ -0,0 +1,28 @@ +_base_ = '../htc/htc_r101_fpn_20e_coco.py' + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True), + output_img=True), + neck=dict( + type='RFP', + rfp_steps=2, + aspp_out_channels=64, + aspp_dilations=(1, 3, 6, 1), + rfp_backbone=dict( + rfp_inplanes=256, + type='DetectoRS_ResNet', + depth=101, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True), + pretrained='torchvision://resnet101', + style='pytorch'))) diff --git a/configs/detectors/detectors_htc_r50_1x_coco.py b/configs/detectors/detectors_htc_r50_1x_coco.py new file mode 100644 index 0000000..0d2fc4f --- /dev/null +++ b/configs/detectors/detectors_htc_r50_1x_coco.py @@ -0,0 +1,28 @@ +_base_ = '../htc/htc_r50_fpn_1x_coco.py' + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True), + output_img=True), + neck=dict( + type='RFP', + rfp_steps=2, + aspp_out_channels=64, + aspp_dilations=(1, 3, 6, 1), + rfp_backbone=dict( + rfp_inplanes=256, + type='DetectoRS_ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True), + pretrained='torchvision://resnet50', + style='pytorch'))) diff --git a/configs/detectors/htc_r50_rfp_1x_coco.py b/configs/detectors/htc_r50_rfp_1x_coco.py new file mode 100644 index 0000000..496104e --- /dev/null +++ b/configs/detectors/htc_r50_rfp_1x_coco.py @@ -0,0 +1,24 @@ +_base_ = '../htc/htc_r50_fpn_1x_coco.py' + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + output_img=True), + neck=dict( + type='RFP', + rfp_steps=2, + aspp_out_channels=64, + aspp_dilations=(1, 3, 6, 1), + rfp_backbone=dict( + rfp_inplanes=256, + type='DetectoRS_ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + conv_cfg=dict(type='ConvAWS'), + pretrained='torchvision://resnet50', + style='pytorch'))) diff --git a/configs/detectors/htc_r50_sac_1x_coco.py b/configs/detectors/htc_r50_sac_1x_coco.py new file mode 100644 index 0000000..72d4db9 --- /dev/null +++ b/configs/detectors/htc_r50_sac_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = '../htc/htc_r50_fpn_1x_coco.py' + +model = dict( + backbone=dict( + type='DetectoRS_ResNet', + conv_cfg=dict(type='ConvAWS'), + sac=dict(type='SAC', use_deform=True), + stage_with_sac=(False, True, True, True))) diff --git a/configs/detectors/metafile.yml b/configs/detectors/metafile.yml new file mode 100644 index 0000000..4bed569 --- /dev/null +++ b/configs/detectors/metafile.yml @@ -0,0 +1,114 @@ +Collections: + - Name: DetectoRS + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - ASPP + - FPN + - RFP + - RPN + - ResNet + - RoIAlign + - SAC + Paper: + URL: https://arxiv.org/abs/2006.02334 + Title: 'DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolution' + README: configs/detectors/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.2.0/mmdet/models/backbones/detectors_resnet.py#L205 + Version: v2.2.0 + +Models: + - Name: cascade_rcnn_r50_rfp_1x_coco + In Collection: DetectoRS + Config: configs/detectors/cascade_rcnn_r50_rfp_1x_coco.py + Metadata: + Training Memory (GB): 7.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detectors/cascade_rcnn_r50_rfp_1x_coco/cascade_rcnn_r50_rfp_1x_coco-8cf51bfd.pth + + - Name: cascade_rcnn_r50_sac_1x_coco + In Collection: DetectoRS + Config: configs/detectors/cascade_rcnn_r50_sac_1x_coco.py + Metadata: + Training Memory (GB): 5.6 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detectors/cascade_rcnn_r50_sac_1x_coco/cascade_rcnn_r50_sac_1x_coco-24bfda62.pth + + - Name: detectors_cascade_rcnn_r50_1x_coco + In Collection: DetectoRS + Config: configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py + Metadata: + Training Memory (GB): 9.9 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_cascade_rcnn_r50_1x_coco/detectors_cascade_rcnn_r50_1x_coco-32a10ba0.pth + + - Name: htc_r50_rfp_1x_coco + In Collection: DetectoRS + Config: configs/detectors/htc_r50_rfp_1x_coco.py + Metadata: + Training Memory (GB): 11.2 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detectors/htc_r50_rfp_1x_coco/htc_r50_rfp_1x_coco-8ff87c51.pth + + - Name: htc_r50_sac_1x_coco + In Collection: DetectoRS + Config: configs/detectors/htc_r50_sac_1x_coco.py + Metadata: + Training Memory (GB): 9.3 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detectors/htc_r50_sac_1x_coco/htc_r50_sac_1x_coco-bfa60c54.pth + + - Name: detectors_htc_r50_1x_coco + In Collection: DetectoRS + Config: configs/detectors/detectors_htc_r50_1x_coco.py + Metadata: + Training Memory (GB): 13.6 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 49.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 42.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detectors/detectors_htc_r50_1x_coco/detectors_htc_r50_1x_coco-329b1453.pth diff --git a/configs/detr/README.md b/configs/detr/README.md new file mode 100644 index 0000000..617a8fb --- /dev/null +++ b/configs/detr/README.md @@ -0,0 +1,27 @@ +# DETR + +## Introduction + + + +We provide the config files for DETR: [End-to-End Object Detection with Transformers](https://arxiv.org/abs/2005.12872). + +```BibTeX +@inproceedings{detr, + author = {Nicolas Carion and + Francisco Massa and + Gabriel Synnaeve and + Nicolas Usunier and + Alexander Kirillov and + Sergey Zagoruyko}, + title = {End-to-End Object Detection with Transformers}, + booktitle = {ECCV}, + year = {2020} +} +``` + +## Results and Models + +| Backbone | Model | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:------:|:--------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | DETR |150e |7.9| | 40.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/detr/detr_r50_8x2_150e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/detr/detr_r50_8x2_150e_coco/detr_r50_8x2_150e_coco_20201130_194835-2c4b8974.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/detr/detr_r50_8x2_150e_coco/detr_r50_8x2_150e_coco_20201130_194835.log.json) | diff --git a/configs/detr/detr_r50_8x2_150e_coco.py b/configs/detr/detr_r50_8x2_150e_coco.py new file mode 100644 index 0000000..892447d --- /dev/null +++ b/configs/detr/detr_r50_8x2_150e_coco.py @@ -0,0 +1,150 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', '../_base_/default_runtime.py' +] +model = dict( + type='DETR', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(3, ), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + bbox_head=dict( + type='DETRHead', + num_classes=80, + in_channels=2048, + transformer=dict( + type='Transformer', + encoder=dict( + type='DetrTransformerEncoder', + num_layers=6, + transformerlayers=dict( + type='BaseTransformerLayer', + attn_cfgs=[ + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1) + ], + feedforward_channels=2048, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'ffn', 'norm'))), + decoder=dict( + type='DetrTransformerDecoder', + return_intermediate=True, + num_layers=6, + transformerlayers=dict( + type='DetrTransformerDecoderLayer', + attn_cfgs=dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1), + feedforward_channels=2048, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'cross_attn', 'norm', + 'ffn', 'norm')), + )), + positional_encoding=dict( + type='SinePositionalEncoding', num_feats=128, normalize=True), + loss_cls=dict( + type='CrossEntropyLoss', + bg_cls_weight=0.1, + use_sigmoid=False, + loss_weight=1.0, + class_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=5.0), + loss_iou=dict(type='GIoULoss', loss_weight=2.0)), + # training and testing settings + train_cfg=dict( + assigner=dict( + type='HungarianAssigner', + cls_cost=dict(type='ClassificationCost', weight=1.), + reg_cost=dict(type='BBoxL1Cost', weight=5.0, box_format='xywh'), + iou_cost=dict(type='IoUCost', iou_mode='giou', weight=2.0))), + test_cfg=dict(max_per_img=100)) +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +# train_pipeline, NOTE the img_scale and the Pad's size_divisor is different +# from the default setting in mmdet. +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='AutoAugment', + policies=[[ + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), (576, 1333), + (608, 1333), (640, 1333), (672, 1333), (704, 1333), + (736, 1333), (768, 1333), (800, 1333)], + multiscale_mode='value', + keep_ratio=True) + ], + [ + dict( + type='Resize', + img_scale=[(400, 1333), (500, 1333), (600, 1333)], + multiscale_mode='value', + keep_ratio=True), + dict( + type='RandomCrop', + crop_type='absolute_range', + crop_size=(384, 600), + allow_negative_crop=True), + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), + (576, 1333), (608, 1333), (640, 1333), + (672, 1333), (704, 1333), (736, 1333), + (768, 1333), (800, 1333)], + multiscale_mode='value', + override=True, + keep_ratio=True) + ]]), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='AdamW', + lr=0.0001, + weight_decay=0.0001, + paramwise_cfg=dict( + custom_keys={'backbone': dict(lr_mult=0.1, decay_mult=1.0)})) +optimizer_config = dict(grad_clip=dict(max_norm=0.1, norm_type=2)) +# learning policy +lr_config = dict(policy='step', step=[100]) +runner = dict(type='EpochBasedRunner', max_epochs=150) diff --git a/configs/detr/detr_r50_8x2_150e_coco_merge.py b/configs/detr/detr_r50_8x2_150e_coco_merge.py new file mode 100644 index 0000000..947cd02 --- /dev/null +++ b/configs/detr/detr_r50_8x2_150e_coco_merge.py @@ -0,0 +1,152 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', '../_base_/default_runtime.py' +] +model = dict( + type='DETRBase', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(3, ), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + bbox_head=dict( + type='DETRProHead', + num_classes=80, + in_channels=2048, + num_vocal=4096, + split_loss=True, + transformer=dict( + type='Transformer', + encoder=dict( + type='DetrTransformerEncoder', + num_layers=6, + transformerlayers=dict( + type='BaseTransformerLayer', + attn_cfgs=[ + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1) + ], + feedforward_channels=2048, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'ffn', 'norm'))), + decoder=dict( + type='DetrTransformerDecoder', + return_intermediate=True, + num_layers=6, + transformerlayers=dict( + type='DetrTransformerDecoderLayer', + attn_cfgs=dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1), + feedforward_channels=2048, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'cross_attn', 'norm', + 'ffn', 'norm')), + )), + positional_encoding=dict( + type='SinePositionalEncoding', num_feats=128, normalize=True), + loss_cls=dict( + type='CrossEntropyLoss', + bg_cls_weight=0.1, + use_sigmoid=False, + loss_weight=1.0, + class_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=5.0), + loss_iou=dict(type='GIoULoss', loss_weight=2.0)), + # training and testing settings + train_cfg=dict( + assigner=dict( + type='HungarianAssigner', + cls_cost=dict(type='ClassificationCost', weight=1.), + reg_cost=dict(type='BBoxL1Cost', weight=5.0, box_format='xywh'), + iou_cost=dict(type='IoUCost', iou_mode='giou', weight=2.0))), + test_cfg=dict(max_per_img=100)) +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +# train_pipeline, NOTE the img_scale and the Pad's size_divisor is different +# from the default setting in mmdet. +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='AutoAugment', + policies=[[ + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), (576, 1333), + (608, 1333), (640, 1333), (672, 1333), (704, 1333), + (736, 1333), (768, 1333), (800, 1333)], + multiscale_mode='value', + keep_ratio=True) + ], + [ + dict( + type='Resize', + img_scale=[(400, 1333), (500, 1333), (600, 1333)], + multiscale_mode='value', + keep_ratio=True), + dict( + type='RandomCrop', + crop_type='absolute_range', + crop_size=(384, 600), + allow_negative_crop=True), + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), + (576, 1333), (608, 1333), (640, 1333), + (672, 1333), (704, 1333), (736, 1333), + (768, 1333), (800, 1333)], + multiscale_mode='value', + override=True, + keep_ratio=True) + ]]), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +data = dict( + samples_per_gpu=4, + workers_per_gpu=4, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='AdamW', + lr=0.0001, + weight_decay=0.0001, + paramwise_cfg=dict( + custom_keys={'backbone': dict(lr_mult=0.1, decay_mult=1.0)})) +optimizer_config = dict(grad_clip=dict(max_norm=0.1, norm_type=2)) +# learning policy +lr_config = dict(policy='step', step=[100]) +runner = dict(type='EpochBasedRunner', max_epochs=150) diff --git a/configs/detr/metafile.yml b/configs/detr/metafile.yml new file mode 100644 index 0000000..45622cf --- /dev/null +++ b/configs/detr/metafile.yml @@ -0,0 +1,33 @@ +Collections: + - Name: DETR + Metadata: + Training Data: COCO + Training Techniques: + - AdamW + - Multi Scale Train + - Gradient Clip + Training Resources: 8x V100 GPUs + Architecture: + - ResNet + - Transformer + Paper: + URL: https://arxiv.org/abs/2005.12872 + Title: 'End-to-End Object Detection with Transformers' + README: configs/detr/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.7.0/mmdet/models/detectors/detr.py#L7 + Version: v2.7.0 + +Models: + - Name: detr_r50_8x2_150e_coco + In Collection: DETR + Config: configs/detr/detr_r50_8x2_150e_coco.py + Metadata: + Training Memory (GB): 7.9 + Epochs: 150 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/detr/detr_r50_8x2_150e_coco/detr_r50_8x2_150e_coco_20201130_194835-2c4b8974.pth diff --git a/configs/double_heads/README.md b/configs/double_heads/README.md new file mode 100644 index 0000000..872211d --- /dev/null +++ b/configs/double_heads/README.md @@ -0,0 +1,22 @@ +# Rethinking Classification and Localization for Object Detection + +## Introduction + + + +```latex +@article{wu2019rethinking, + title={Rethinking Classification and Localization for Object Detection}, + author={Yue Wu and Yinpeng Chen and Lu Yuan and Zicheng Liu and Lijuan Wang and Hongzhi Li and Yun Fu}, + year={2019}, + eprint={1904.06493}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +## Results and models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| R-50-FPN | pytorch | 1x | 6.8 | 9.5 | 40.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/double_heads/dh_faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/double_heads/dh_faster_rcnn_r50_fpn_1x_coco/dh_faster_rcnn_r50_fpn_1x_coco_20200130-586b67df.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/double_heads/dh_faster_rcnn_r50_fpn_1x_coco/dh_faster_rcnn_r50_fpn_1x_coco_20200130_220238.log.json) | diff --git a/configs/double_heads/dh_faster_rcnn_r50_fpn_1x_coco.py b/configs/double_heads/dh_faster_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..9b8118b --- /dev/null +++ b/configs/double_heads/dh_faster_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,23 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + type='DoubleHeadRoIHead', + reg_roi_scale_factor=1.3, + bbox_head=dict( + _delete_=True, + type='DoubleConvFCBBoxHead', + num_convs=4, + num_fcs=2, + in_channels=256, + conv_out_channels=1024, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=2.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=2.0)))) diff --git a/configs/double_heads/metafile.yml b/configs/double_heads/metafile.yml new file mode 100644 index 0000000..6fe9b7a --- /dev/null +++ b/configs/double_heads/metafile.yml @@ -0,0 +1,41 @@ +Collections: + - Name: Rethinking Classification and Localization for Object Detection + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - RPN + - ResNet + - RoIAlign + Paper: + URL: https://arxiv.org/pdf/1904.06493 + Title: 'Rethinking Classification and Localization for Object Detection' + README: configs/double_heads/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/roi_heads/double_roi_head.py#L6 + Version: v2.0.0 + +Models: + - Name: dh_faster_rcnn_r50_fpn_1x_coco + In Collection: Rethinking Classification and Localization for Object Detection + Config: configs/double_heads/dh_faster_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.8 + inference time (ms/im): + - value: 105.26 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/double_heads/dh_faster_rcnn_r50_fpn_1x_coco/dh_faster_rcnn_r50_fpn_1x_coco_20200130-586b67df.pth diff --git a/configs/dynamic_rcnn/README.md b/configs/dynamic_rcnn/README.md new file mode 100644 index 0000000..2b087c3 --- /dev/null +++ b/configs/dynamic_rcnn/README.md @@ -0,0 +1,20 @@ +# Dynamic R-CNN: Towards High Quality Object Detection via Dynamic Training + +## Introduction + + + +``` +@article{DynamicRCNN, + author = {Hongkai Zhang and Hong Chang and Bingpeng Ma and Naiyan Wang and Xilin Chen}, + title = {Dynamic {R-CNN}: Towards High Quality Object Detection via Dynamic Training}, + journal = {arXiv preprint arXiv:2004.06002}, + year = {2020} +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | pytorch | 1x | 3.8 | | 38.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x/dynamic_rcnn_r50_fpn_1x-62a3f276.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x/dynamic_rcnn_r50_fpn_1x_20200618_095048.log.json) | diff --git a/configs/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x_coco.py b/configs/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..f2deb99 --- /dev/null +++ b/configs/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,28 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + type='DynamicRoIHead', + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + train_cfg=dict( + rpn_proposal=dict(nms=dict(iou_threshold=0.85)), + rcnn=dict( + dynamic_rcnn=dict( + iou_topk=75, + beta_topk=10, + update_iter_interval=100, + initial_iou=0.4, + initial_beta=1.0))), + test_cfg=dict(rpn=dict(nms=dict(iou_threshold=0.85)))) diff --git a/configs/dynamic_rcnn/metafile.yml b/configs/dynamic_rcnn/metafile.yml new file mode 100644 index 0000000..fec43db --- /dev/null +++ b/configs/dynamic_rcnn/metafile.yml @@ -0,0 +1,35 @@ +Collections: + - Name: Dynamic R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Dynamic R-CNN + - FPN + - RPN + - ResNet + - RoIAlign + Paper: + URL: https://arxiv.org/pdf/2004.06002 + Title: 'Dynamic R-CNN: Towards High Quality Object Detection via Dynamic Training' + README: configs/dynamic_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.2.0/mmdet/models/roi_heads/dynamic_roi_head.py#L11 + Version: v2.2.0 + +Models: + - Name: dynamic_rcnn_r50_fpn_1x_coco + In Collection: Dynamic R-CNN + Config: configs/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.8 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/dynamic_rcnn/dynamic_rcnn_r50_fpn_1x/dynamic_rcnn_r50_fpn_1x-62a3f276.pth diff --git a/configs/empirical_attention/README.md b/configs/empirical_attention/README.md new file mode 100644 index 0000000..f8647bd --- /dev/null +++ b/configs/empirical_attention/README.md @@ -0,0 +1,23 @@ +# An Empirical Study of Spatial Attention Mechanisms in Deep Networks + +## Introduction + + + +```latex +@article{zhu2019empirical, + title={An Empirical Study of Spatial Attention Mechanisms in Deep Networks}, + author={Zhu, Xizhou and Cheng, Dazhi and Zhang, Zheng and Lin, Stephen and Dai, Jifeng}, + journal={arXiv preprint arXiv:1904.05873}, + year={2019} +} +``` + +## Results and Models + +| Backbone | Attention Component | DCN | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------------------:|:----:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | 1111 | N | 1x | 8.0 | 13.8 | 40.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco/faster_rcnn_r50_fpn_attention_1111_1x_coco_20200130-403cccba.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco/faster_rcnn_r50_fpn_attention_1111_1x_coco_20200130_210344.log.json) | +| R-50 | 0010 | N | 1x | 4.2 | 18.4 | 39.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco/faster_rcnn_r50_fpn_attention_0010_1x_coco_20200130-7cb0c14d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco/faster_rcnn_r50_fpn_attention_0010_1x_coco_20200130_210125.log.json) | +| R-50 | 1111 | Y | 1x | 8.0 | 12.7 | 42.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco_20200130-8b2523a6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco_20200130_204442.log.json) | +| R-50 | 0010 | Y | 1x | 4.2 | 17.1 | 42.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco_20200130-1a2e831d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco_20200130_210410.log.json) | diff --git a/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco.py b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco.py new file mode 100644 index 0000000..a544e3a --- /dev/null +++ b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco.py @@ -0,0 +1,13 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict(plugins=[ + dict( + cfg=dict( + type='GeneralizedAttention', + spatial_range=-1, + num_heads=8, + attention_type='0010', + kv_stride=2), + stages=(False, False, True, True), + position='after_conv2') + ])) diff --git a/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco.py b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco.py new file mode 100644 index 0000000..bbefd27 --- /dev/null +++ b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + plugins=[ + dict( + cfg=dict( + type='GeneralizedAttention', + spatial_range=-1, + num_heads=8, + attention_type='0010', + kv_stride=2), + stages=(False, False, True, True), + position='after_conv2') + ], + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco.py b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco.py new file mode 100644 index 0000000..13a4645 --- /dev/null +++ b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco.py @@ -0,0 +1,13 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict(plugins=[ + dict( + cfg=dict( + type='GeneralizedAttention', + spatial_range=-1, + num_heads=8, + attention_type='1111', + kv_stride=2), + stages=(False, False, True, True), + position='after_conv2') + ])) diff --git a/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco.py b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco.py new file mode 100644 index 0000000..b1f26c0 --- /dev/null +++ b/configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + plugins=[ + dict( + cfg=dict( + type='GeneralizedAttention', + spatial_range=-1, + num_heads=8, + attention_type='1111', + kv_stride=2), + stages=(False, False, True, True), + position='after_conv2') + ], + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) diff --git a/configs/empirical_attention/metafile.yml b/configs/empirical_attention/metafile.yml new file mode 100644 index 0000000..923bcb2 --- /dev/null +++ b/configs/empirical_attention/metafile.yml @@ -0,0 +1,103 @@ +Collections: + - Name: Empirical Attention + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Deformable Convolution + - FPN + - RPN + - ResNet + - RoIAlign + - Spatial Attention + Paper: + URL: https://arxiv.org/pdf/1904.05873 + Title: 'An Empirical Study of Spatial Attention Mechanisms in Deep Networks' + README: configs/empirical_attention/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/ops/generalized_attention.py#L10 + Version: v2.0.0 + +Models: + - Name: faster_rcnn_r50_fpn_attention_1111_1x_coco + In Collection: Empirical Attention + Config: configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco.py + Metadata: + Training Memory (GB): 8.0 + inference time (ms/im): + - value: 72.46 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_1111_1x_coco/faster_rcnn_r50_fpn_attention_1111_1x_coco_20200130-403cccba.pth + + - Name: faster_rcnn_r50_fpn_attention_0010_1x_coco + In Collection: Empirical Attention + Config: configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco.py + Metadata: + Training Memory (GB): 4.2 + inference time (ms/im): + - value: 54.35 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_0010_1x_coco/faster_rcnn_r50_fpn_attention_0010_1x_coco_20200130-7cb0c14d.pth + + - Name: faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco + In Collection: Empirical Attention + Config: configs/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco.py + Metadata: + Training Memory (GB): 8.0 + inference time (ms/im): + - value: 78.74 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco/faster_rcnn_r50_fpn_attention_1111_dcn_1x_coco_20200130-8b2523a6.pth + + - Name: faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco + In Collection: Empirical Attention + Config: configs/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco.py + Metadata: + Training Memory (GB): 4.2 + inference time (ms/im): + - value: 58.48 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/empirical_attention/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco/faster_rcnn_r50_fpn_attention_0010_dcn_1x_coco_20200130-1a2e831d.pth diff --git a/configs/fast_rcnn/README.md b/configs/fast_rcnn/README.md new file mode 100644 index 0000000..3be862a --- /dev/null +++ b/configs/fast_rcnn/README.md @@ -0,0 +1,16 @@ +# Fast R-CNN + +## Introduction + + + +```latex +@inproceedings{girshick2015fast, + title={Fast r-cnn}, + author={Girshick, Ross}, + booktitle={Proceedings of the IEEE international conference on computer vision}, + year={2015} +} +``` + +## Results and models diff --git a/configs/fast_rcnn/fast_rcnn_r101_caffe_fpn_1x_coco.py b/configs/fast_rcnn/fast_rcnn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..3ab8e98 --- /dev/null +++ b/configs/fast_rcnn/fast_rcnn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './fast_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/fast_rcnn/fast_rcnn_r101_fpn_1x_coco.py b/configs/fast_rcnn/fast_rcnn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..83852b2 --- /dev/null +++ b/configs/fast_rcnn/fast_rcnn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './fast_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/fast_rcnn/fast_rcnn_r101_fpn_2x_coco.py b/configs/fast_rcnn/fast_rcnn_r101_fpn_2x_coco.py new file mode 100644 index 0000000..c220885 --- /dev/null +++ b/configs/fast_rcnn/fast_rcnn_r101_fpn_2x_coco.py @@ -0,0 +1,6 @@ +_base_ = './fast_rcnn_r50_fpn_2x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/fast_rcnn/fast_rcnn_r50_caffe_fpn_1x_coco.py b/configs/fast_rcnn/fast_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..f1b29ef --- /dev/null +++ b/configs/fast_rcnn/fast_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,48 @@ +_base_ = './fast_rcnn_r50_fpn_1x_coco.py' + +model = dict( + backbone=dict( + norm_cfg=dict(type='BN', requires_grad=False), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) + +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=2000), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'proposals', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=None), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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='ToTensor', keys=['proposals']), + dict( + type='ToDataContainer', + fields=[dict(key='proposals', stack=False)]), + dict(type='Collect', keys=['img', 'proposals']), + ]) +] +data = dict( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py b/configs/fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..d2f080e --- /dev/null +++ b/configs/fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,52 @@ +_base_ = [ + '../_base_/models/fast_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=2000), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'proposals', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=None), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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='ToTensor', keys=['proposals']), + dict( + type='ToDataContainer', + fields=[dict(key='proposals', stack=False)]), + dict(type='Collect', keys=['img', 'proposals']), + ]) +] +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + proposal_file=data_root + 'proposals/rpn_r50_fpn_1x_train2017.pkl', + pipeline=train_pipeline), + val=dict( + proposal_file=data_root + 'proposals/rpn_r50_fpn_1x_val2017.pkl', + pipeline=test_pipeline), + test=dict( + proposal_file=data_root + 'proposals/rpn_r50_fpn_1x_val2017.pkl', + pipeline=test_pipeline)) diff --git a/configs/fast_rcnn/fast_rcnn_r50_fpn_2x_coco.py b/configs/fast_rcnn/fast_rcnn_r50_fpn_2x_coco.py new file mode 100644 index 0000000..228e856 --- /dev/null +++ b/configs/fast_rcnn/fast_rcnn_r50_fpn_2x_coco.py @@ -0,0 +1,5 @@ +_base_ = './fast_rcnn_r50_fpn_1x_coco.py' + +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/faster_rcnn/README.md b/configs/faster_rcnn/README.md new file mode 100644 index 0000000..772a6c4 --- /dev/null +++ b/configs/faster_rcnn/README.md @@ -0,0 +1,67 @@ +# Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks + +## Introduction + + + +```latex +@article{Ren_2017, + title={Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks}, + journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, + publisher={Institute of Electrical and Electronics Engineers (IEEE)}, + author={Ren, Shaoqing and He, Kaiming and Girshick, Ross and Sun, Jian}, + year={2017}, + month={Jun}, +} +``` + +## Results and models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| R-50-DC5 | caffe | 1x | - | - | 37.2 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco/faster_rcnn_r50_caffe_dc5_1x_coco_20201030_151909-531f0f43.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco/faster_rcnn_r50_caffe_dc5_1x_coco_20201030_151909.log.json) | +| R-50-FPN | caffe | 1x | 3.8 | | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco/faster_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.378_20200504_180032-c5925ee5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco/faster_rcnn_r50_caffe_fpn_1x_coco_20200504_180032.log.json) | +| R-50-FPN | pytorch | 1x | 4.0 | 21.4 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130_204655.log.json) | +| R-50-FPN | pytorch | 2x | - | - | 38.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_20200504_210434.log.json) | +| R-101-FPN | caffe | 1x | 5.7 | | 39.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco/faster_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.398_20200504_180057-b269e9dd.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco/faster_rcnn_r101_caffe_fpn_1x_coco_20200504_180057.log.json) | +| R-101-FPN | pytorch | 1x | 6.0 | 15.6 | 39.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_1x_coco/faster_rcnn_r101_fpn_1x_coco_20200130-f513f705.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_1x_coco/faster_rcnn_r101_fpn_1x_coco_20200130_204655.log.json) | +| R-101-FPN | pytorch | 2x | - | - | 39.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_20200504_210455.log.json) | +| X-101-32x4d-FPN | pytorch | 1x | 7.2 | 13.8 | 41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco/faster_rcnn_x101_32x4d_fpn_1x_coco_20200203-cff10310.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco/faster_rcnn_x101_32x4d_fpn_1x_coco_20200203_000520.log.json) | +| X-101-32x4d-FPN | pytorch | 2x | - | - | 41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco/faster_rcnn_x101_32x4d_fpn_2x_coco_bbox_mAP-0.412_20200506_041400-64a12c0b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco/faster_rcnn_x101_32x4d_fpn_2x_coco_20200506_041400.log.json) | +| X-101-64x4d-FPN | pytorch | 1x | 10.3 | 9.4 | 42.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco/faster_rcnn_x101_64x4d_fpn_1x_coco_20200204-833ee192.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco/faster_rcnn_x101_64x4d_fpn_1x_coco_20200204_134340.log.json) | +| X-101-64x4d-FPN | pytorch | 2x | - | - | 41.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco/faster_rcnn_x101_64x4d_fpn_2x_coco_20200512_161033-5961fa95.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco/faster_rcnn_x101_64x4d_fpn_2x_coco_20200512_161033.log.json) | + +## Different regression loss + +We trained with R-50-FPN pytorch style backbone for 1x schedule. + +| Backbone | Loss type | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-------: | :------: | :------------: | :----: | :------: | :--------: | +| R-50-FPN | L1Loss | 4.0 | 21.4 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130_204655.log.json) | +| R-50-FPN | IoULoss | | | 37.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_iou_1x_coco-fdd207f3.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_iou_1x_coco_20200506_095954.log.json) | +| R-50-FPN | GIoULoss | | | 37.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_giou_1x_coco-0eada910.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_giou_1x_coco_20200505_161120.log.json) | +| R-50-FPN | BoundedIoULoss | | | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_bounded_iou_1x_coco-98ad993b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_bounded_iou_1x_coco_20200505_160738.log.json) | + +## Pre-trained Models + +We also train some models with longer schedules and multi-scale training. The users could finetune them for downstream tasks. + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| [R-50-DC5](./faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py) | caffe | 1x | - | | 37.4 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco_20201028_233851-b33d21b9.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco_20201028_233851.log.json) | +| [R-50-DC5](./faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py) | caffe | 3x | - | | 38.7 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco_20201028_002107-34a53b2c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco_20201028_002107.log.json) | +| [R-50-FPN](./faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py) | caffe | 2x | 3.7 | | 39.7 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco_bbox_mAP-0.397_20200504_231813-10b2de58.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco_20200504_231813.log.json) | +| [R-50-FPN](./faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py) | caffe | 3x | 3.7 | | 39.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054-1f77628b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054.log.json) | +| [R-50-FPN](./faster_rcnn_r50_fpn_mstrain_3x_coco.py) | pytorch | 3x | 3.9 | | 40.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822-e10bd31c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822.log.json) | +| [R-101-FPN](./faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py) | caffe | 3x | 5.6 | | 42.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco_20210526_095742-a7ae426d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco_20210526_095742.log.json) | +| [R-101-FPN](./faster_rcnn_r101_fpn_mstrain_3x_coco.py) | pytorch | 3x | 5.8 | | 41.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco/faster_rcnn_r101_fpn_mstrain_3x_coco_20210524_110822-4d4d2ca8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco/faster_rcnn_r101_fpn_mstrain_3x_coco_20210524_110822.log.json) | +| [X-101-32x4d-FPN](./faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py) | pytorch | 3x | 7.0 | | 42.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco_20210524_124151-16b9b260.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco_20210524_124151.log.json) | +| [X-101-32x8d-FPN](./faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py) | pytorch | 3x | 10.1 | | 42.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco_20210604_182954-002e082a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco_20210604_182954.log.json) | +| [X-101-64x4d-FPN](./faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py) | pytorch | 3x | 10.0 | | 43.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco_20210524_124528-26c63de6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco_20210524_124528.log.json) | + +We further finetune some pre-trained models on the COCO subsets, which only contain only a few of the 80 categories. + +| Backbone | Style | Class name | Pre-traind model | Mem (GB) | box AP | Config | Download | +| ------------------------------------------------------------ | ----- | ------------------ | ------------------------------------------------------------ | -------- | ------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| [R-50-FPN](./faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person.py) | caffe | person | [R-50-FPN-Caffe-3x](./faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py) | 3.7 | 55.8 | [config](./faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco-person/faster_rcnn_r50_fpn_1x_coco-person_20201216_175929-d022e227.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco-person/faster_rcnn_r50_fpn_1x_coco-person_20201216_175929.log.json) | +| [R-50-FPN](./faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person-bicycle-car.py) | caffe | person-bicycle-car | [R-50-FPN-Caffe-3x](./faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py) | 3.7 | 44.1 | [config](./faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person-bicycle-car.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco-person-bicycle-car/faster_rcnn_r50_fpn_1x_coco-person-bicycle-car_20201216_173117-6eda6d92.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco-person-bicycle-car/faster_rcnn_r50_fpn_1x_coco-person-bicycle-car_20201216_173117.log.json) | diff --git a/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..c6f078c --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './faster_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..6a13fe9 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py @@ -0,0 +1,49 @@ +_base_ = 'faster_rcnn_r50_fpn_mstrain_3x_coco.py' + +model = dict( + backbone=dict( + depth=101, + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) + +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..1de53a6 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py b/configs/faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py new file mode 100644 index 0000000..0d41599 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_2x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..0b498bb --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco.py @@ -0,0 +1,7 @@ +_base_ = 'faster_rcnn_r50_fpn_mstrain_3x_coco.py' + +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_c4_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_c4_1x_coco.py new file mode 100644 index 0000000..92344a1 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_c4_1x_coco.py @@ -0,0 +1,39 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_caffe_c4.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco.py new file mode 100644 index 0000000..ee2010c --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco.py @@ -0,0 +1,37 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_caffe_dc5.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py new file mode 100644 index 0000000..14eaef2 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py @@ -0,0 +1,42 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_caffe_dc5.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py new file mode 100644 index 0000000..403747f --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py @@ -0,0 +1,4 @@ +_base_ = './faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py' +# learning policy +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..56c01bd --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,41 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_90k_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_90k_coco.py new file mode 100644 index 0000000..b5aea6a --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_90k_coco.py @@ -0,0 +1,15 @@ +_base_ = 'faster_rcnn_r50_caffe_fpn_1x_coco.py' + +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[60000, 80000]) + +# Runner type +runner = dict(_delete_=True, type='IterBasedRunner', max_iters=90000) + +checkpoint_config = dict(interval=10000) +evaluation = dict(interval=10000, metric='bbox') diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person-bicycle-car.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person-bicycle-car.py new file mode 100644 index 0000000..4f1f376 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person-bicycle-car.py @@ -0,0 +1,9 @@ +_base_ = './faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py' +model = dict(roi_head=dict(bbox_head=dict(num_classes=3))) +classes = ('person', 'bicycle', 'car') +data = dict( + train=dict(classes=classes), + val=dict(classes=classes), + test=dict(classes=classes)) + +load_from = 'https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_bbox_mAP-0.398_20200504_163323-30042637.pth' # noqa diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person.py new file mode 100644 index 0000000..b5dfb4f --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco-person.py @@ -0,0 +1,9 @@ +_base_ = './faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py' +model = dict(roi_head=dict(bbox_head=dict(num_classes=1))) +classes = ('person', ) +data = dict( + train=dict(classes=classes), + val=dict(classes=classes), + test=dict(classes=classes)) + +load_from = 'https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_bbox_mAP-0.398_20200504_163323-30042637.pth' # noqa diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py new file mode 100644 index 0000000..f807a19 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py @@ -0,0 +1,46 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py new file mode 100644 index 0000000..df58973 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..9eeaace --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py @@ -0,0 +1,47 @@ +_base_ = 'faster_rcnn_r50_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) + +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_90k_coco.py b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_90k_coco.py new file mode 100644 index 0000000..74dca24 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_90k_coco.py @@ -0,0 +1,15 @@ +_base_ = 'faster_rcnn_r50_caffe_fpn_mstrain_1x_coco.py' + +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[60000, 80000]) + +# Runner type +runner = dict(_delete_=True, type='IterBasedRunner', max_iters=90000) + +checkpoint_config = dict(interval=10000) +evaluation = dict(interval=10000, metric='bbox') diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..009bd93 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py new file mode 100644 index 0000000..e77a7fa --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_2x.py', '../_base_/default_runtime.py' +] diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_bounded_iou_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_bounded_iou_1x_coco.py new file mode 100644 index 0000000..648081f --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_bounded_iou_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + bbox_head=dict( + reg_decoded_bbox=True, + loss_bbox=dict(type='BoundedIoULoss', loss_weight=10.0)))) diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_ciou_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_ciou_1x_coco.py new file mode 100644 index 0000000..886d566 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_ciou_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + bbox_head=dict( + reg_decoded_bbox=True, + loss_bbox=dict(type='CIoULoss', loss_weight=12.0)))) diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_giou_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_giou_1x_coco.py new file mode 100644 index 0000000..5556c49 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_giou_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + bbox_head=dict( + reg_decoded_bbox=True, + loss_bbox=dict(type='GIoULoss', loss_weight=10.0)))) diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_iou_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_iou_1x_coco.py new file mode 100644 index 0000000..ddf663e --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_iou_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + bbox_head=dict( + reg_decoded_bbox=True, + loss_bbox=dict(type='IoULoss', loss_weight=10.0)))) diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..faf8f92 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco.py @@ -0,0 +1,3 @@ +_base_ = [ + '../common/mstrain_3x_coco.py', '../_base_/models/faster_rcnn_r50_fpn.py' +] diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_ohem_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_ohem_1x_coco.py new file mode 100644 index 0000000..f897e7c --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_ohem_1x_coco.py @@ -0,0 +1,2 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict(train_cfg=dict(rcnn=dict(sampler=dict(type='OHEMSampler')))) diff --git a/configs/faster_rcnn/faster_rcnn_r50_fpn_soft_nms_1x_coco.py b/configs/faster_rcnn/faster_rcnn_r50_fpn_soft_nms_1x_coco.py new file mode 100644 index 0000000..759ae3a --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_r50_fpn_soft_nms_1x_coco.py @@ -0,0 +1,12 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + test_cfg=dict( + rcnn=dict( + score_thr=0.05, + nms=dict(type='soft_nms', iou_threshold=0.5), + max_per_img=100))) diff --git a/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..3808c9f --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco.py new file mode 100644 index 0000000..e93f5d8 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco.py @@ -0,0 +1,14 @@ +_base_ = './faster_rcnn_r50_fpn_2x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..f55985d --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py @@ -0,0 +1,16 @@ +_base_ = [ + '../common/mstrain_3x_coco.py', '../_base_/models/faster_rcnn_r50_fpn.py' +] +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..a5d5aeb --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py @@ -0,0 +1,62 @@ +_base_ = [ + '../common/mstrain_3x_coco.py', '../_base_/models/faster_rcnn_r50_fpn.py' +] +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=8, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + style='pytorch', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnext101_32x8d'))) + +# ResNeXt-101-32x8d model trained with Caffe2 at FB, +# so the mean and std need to be changed. +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], + std=[57.375, 57.120, 58.395], + to_rgb=False) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..8bf2b65 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco.py new file mode 100644 index 0000000..7ea9b2d --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco.py @@ -0,0 +1,14 @@ +_base_ = './faster_rcnn_r50_fpn_2x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py b/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..80397f4 --- /dev/null +++ b/configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py @@ -0,0 +1,16 @@ +_base_ = [ + '../common/mstrain_3x_coco.py', '../_base_/models/faster_rcnn_r50_fpn.py' +] +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/faster_rcnn/metafile.yml b/configs/faster_rcnn/metafile.yml new file mode 100644 index 0000000..97faf53 --- /dev/null +++ b/configs/faster_rcnn/metafile.yml @@ -0,0 +1,383 @@ +Collections: + - Name: Faster R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - RPN + - ResNet + - RoIPool + Paper: + URL: https://arxiv.org/abs/1506.01497 + Title: 'Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks' + README: configs/faster_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/faster_rcnn.py#L6 + Version: v2.0.0 + +Models: + - Name: faster_rcnn_r50_caffe_dc5_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_1x_coco/faster_rcnn_r50_caffe_dc5_1x_coco_20201030_151909-531f0f43.pth + + - Name: faster_rcnn_r50_caffe_fpn_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.8 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco/faster_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.378_20200504_180032-c5925ee5.pth + + - Name: faster_rcnn_r50_fpn_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.0 + inference time (ms/im): + - value: 46.73 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth + + - Name: faster_rcnn_r50_fpn_2x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_fpn_2x_coco.py + Metadata: + Training Memory (GB): 4.0 + inference time (ms/im): + - value: 46.73 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth + + - Name: faster_rcnn_r101_caffe_fpn_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.7 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_caffe_fpn_1x_coco/faster_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.398_20200504_180057-b269e9dd.pth + + - Name: faster_rcnn_r101_fpn_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 64.1 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_1x_coco/faster_rcnn_r101_fpn_1x_coco_20200130-f513f705.pth + + - Name: faster_rcnn_r101_fpn_2x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 64.1 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth + + - Name: faster_rcnn_x101_32x4d_fpn_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.2 + inference time (ms/im): + - value: 72.46 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco/faster_rcnn_x101_32x4d_fpn_1x_coco_20200203-cff10310.pth + + - Name: faster_rcnn_x101_32x4d_fpn_2x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco.py + Metadata: + Training Memory (GB): 7.2 + inference time (ms/im): + - value: 72.46 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_2x_coco/faster_rcnn_x101_32x4d_fpn_2x_coco_bbox_mAP-0.412_20200506_041400-64a12c0b.pth + + - Name: faster_rcnn_x101_64x4d_fpn_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 10.3 + inference time (ms/im): + - value: 106.38 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_1x_coco/faster_rcnn_x101_64x4d_fpn_1x_coco_20200204-833ee192.pth + + - Name: faster_rcnn_x101_64x4d_fpn_2x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco.py + Metadata: + Training Memory (GB): 10.3 + inference time (ms/im): + - value: 106.38 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_2x_coco/faster_rcnn_x101_64x4d_fpn_2x_coco_20200512_161033-5961fa95.pth + + - Name: faster_rcnn_r50_fpn_iou_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_fpn_iou_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_iou_1x_coco-fdd207f3.pth + + - Name: faster_rcnn_r50_fpn_giou_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_fpn_giou_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_giou_1x_coco-0eada910.pth + + - Name: faster_rcnn_r50_fpn_bounded_iou_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_fpn_bounded_iou_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_bounded_iou_1x_coco-98ad993b.pth + + - Name: faster_rcnn_r50_caffe_dc5_mstrain_1x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco/faster_rcnn_r50_caffe_dc5_mstrain_1x_coco_20201028_233851-b33d21b9.pth + + - Name: faster_rcnn_r50_caffe_dc5_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco.py + Metadata: + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco/faster_rcnn_r50_caffe_dc5_mstrain_3x_coco_20201028_002107-34a53b2c.pth + + - Name: faster_rcnn_r50_caffe_fpn_mstrain_2x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco.py + Metadata: + Training Memory (GB): 4.3 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco/faster_rcnn_r50_caffe_fpn_mstrain_2x_coco_bbox_mAP-0.397_20200504_231813-10b2de58.pth + + - Name: faster_rcnn_r50_caffe_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 3.7 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054-1f77628b.pth + + - Name: faster_rcnn_r50_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 3.9 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_mstrain_3x_coco/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822-e10bd31c.pth + + - Name: faster_rcnn_r101_caffe_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.6 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco/faster_rcnn_r101_caffe_fpn_mstrain_3x_coco_20210526_095742-a7ae426d.pth + + - Name: faster_rcnn_r101_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.8 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_mstrain_3x_coco/faster_rcnn_r101_fpn_mstrain_3x_coco_20210524_110822-4d4d2ca8.pth + + - Name: faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 7.0 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco/faster_rcnn_x101_32x4d_fpn_mstrain_3x_coco_20210524_124151-16b9b260.pth + + - Name: faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 10.1 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco/faster_rcnn_x101_32x8d_fpn_mstrain_3x_coco_20210604_182954-002e082a.pth + + - Name: faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco + In Collection: Faster R-CNN + Config: configs/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 10.0 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco/faster_rcnn_x101_64x4d_fpn_mstrain_3x_coco_20210524_124528-26c63de6.pth diff --git a/configs/fcos/README.md b/configs/fcos/README.md new file mode 100644 index 0000000..dd20d57 --- /dev/null +++ b/configs/fcos/README.md @@ -0,0 +1,35 @@ +# FCOS: Fully Convolutional One-Stage Object Detection + +## Introduction + + + +```latex +@article{tian2019fcos, + title={FCOS: Fully Convolutional One-Stage Object Detection}, + author={Tian, Zhi and Shen, Chunhua and Chen, Hao and He, Tong}, + journal={arXiv preprint arXiv:1904.01355}, + year={2019} +} +``` + +## Results and Models + +| Backbone | Style | GN | MS train | Tricks | DCN | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:-------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | caffe | Y | N | N | N | 1x | 3.6 | 22.7 | 36.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco/fcos_r50_caffe_fpn_gn-head_1x_coco-821213aa.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco/20201227_180009.log.json) | +| R-50 | caffe | Y | N | Y | N | 1x | 3.7 | - | 38.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco-0a0d75a8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco/20210105_135818.log.json)| +| R-50 | caffe | Y | N | Y | Y | 1x | 3.8 | - | 42.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco-ae4d8b3d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco/20210105_224556.log.json)| +| R-101 | caffe | Y | N | N | N | 1x | 5.5 | 17.3 | 39.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco/fcos_r101_caffe_fpn_gn-head_1x_coco-0e37b982.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco/20210103_155046.log.json) | + +| Backbone | Style | GN | MS train | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | caffe | Y | Y | 2x | 2.6 | 22.9 | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco-d92ceeea.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco/20201227_161900.log.json) | +| R-101 | caffe | Y | Y | 2x | 5.5 | 17.3 | 40.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco-511424d6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco/20210103_155046.log.json) | +| X-101 | pytorch | Y | Y | 2x | 10.0 | 9.7 | 42.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco-ede514a8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco/20210114_133041.log.json) | + +**Notes:** + +- The X-101 backbone is X-101-64x4d. +- Tricks means setting `norm_on_bbox`, `centerness_on_reg`, `center_sampling` as `True`. +- DCN means using `DCNv2` in both backbone and head. diff --git a/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco.py b/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco.py new file mode 100644 index 0000000..2699bdb --- /dev/null +++ b/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco.py @@ -0,0 +1,54 @@ +_base_ = 'fcos_r50_caffe_fpn_gn-head_1x_coco.py' + +model = dict( + backbone=dict( + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + bbox_head=dict( + norm_on_bbox=True, + centerness_on_reg=True, + dcn_on_last_conv=False, + center_sampling=True, + conv_bias=True, + loss_bbox=dict(type='GIoULoss', loss_weight=1.0)), + # training and testing settings + test_cfg=dict(nms=dict(type='nms', iou_threshold=0.6))) + +# dataset settings +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +optimizer_config = dict(_delete_=True, grad_clip=None) + +lr_config = dict(warmup='linear') diff --git a/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py b/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py new file mode 100644 index 0000000..cf93c91 --- /dev/null +++ b/configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py @@ -0,0 +1,56 @@ +_base_ = 'fcos_r50_caffe_fpn_gn-head_1x_coco.py' + +model = dict( + backbone=dict( + dcn=dict(type='DCNv2', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True), + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + bbox_head=dict( + norm_on_bbox=True, + centerness_on_reg=True, + dcn_on_last_conv=True, + center_sampling=True, + conv_bias=True, + loss_bbox=dict(type='GIoULoss', loss_weight=1.0)), + # training and testing settings + test_cfg=dict(nms=dict(type='nms', iou_threshold=0.6))) + +# dataset settings +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +optimizer_config = dict(_delete_=True, grad_clip=None) + +lr_config = dict(warmup='linear') diff --git a/configs/fcos/fcos_center_r50_caffe_fpn_gn-head_1x_coco.py b/configs/fcos/fcos_center_r50_caffe_fpn_gn-head_1x_coco.py new file mode 100644 index 0000000..9f502e7 --- /dev/null +++ b/configs/fcos/fcos_center_r50_caffe_fpn_gn-head_1x_coco.py @@ -0,0 +1,2 @@ +_base_ = './fcos_r50_caffe_fpn_gn-head_1x_coco.py' +model = dict(bbox_head=dict(center_sampling=True, center_sample_radius=1.5)) diff --git a/configs/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco.py b/configs/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco.py new file mode 100644 index 0000000..45bea48 --- /dev/null +++ b/configs/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './fcos_r50_caffe_fpn_gn-head_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron/resnet101_caffe'))) diff --git a/configs/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py b/configs/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py new file mode 100644 index 0000000..f4d36f1 --- /dev/null +++ b/configs/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py @@ -0,0 +1,47 @@ +_base_ = './fcos_r50_caffe_fpn_gn-head_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron/resnet101_caffe'))) +img_norm_cfg = dict( + mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco.py b/configs/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco.py new file mode 100644 index 0000000..955787b --- /dev/null +++ b/configs/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco.py @@ -0,0 +1,106 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# model settings +model = dict( + type='FCOS', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron/resnet50_caffe')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_output', # use P5 + num_outs=5, + relu_before_extra_convs=True), + bbox_head=dict( + type='FCOSHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + strides=[8, 16, 32, 64, 128], + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='IoULoss', loss_weight=1.0), + loss_centerness=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), + # training and testing settings + train_cfg=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100)) +img_norm_cfg = dict( + mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + lr=0.01, paramwise_cfg=dict(bias_lr_mult=2., bias_decay_mult=0.)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='constant', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[8, 11]) +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/fcos/fcos_r50_caffe_fpn_gn-head_4x4_1x_coco.py b/configs/fcos/fcos_r50_caffe_fpn_gn-head_4x4_1x_coco.py new file mode 100644 index 0000000..2816b16 --- /dev/null +++ b/configs/fcos/fcos_r50_caffe_fpn_gn-head_4x4_1x_coco.py @@ -0,0 +1,4 @@ +# TODO: Remove this config after benchmarking all related configs +_base_ = 'fcos_r50_caffe_fpn_gn-head_1x_coco.py' + +data = dict(samples_per_gpu=4, workers_per_gpu=4) diff --git a/configs/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py b/configs/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py new file mode 100644 index 0000000..497d03f --- /dev/null +++ b/configs/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py @@ -0,0 +1,39 @@ +_base_ = './fcos_r50_caffe_fpn_gn-head_1x_coco.py' +img_norm_cfg = dict( + mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco.py b/configs/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco.py new file mode 100644 index 0000000..e70e465 --- /dev/null +++ b/configs/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco.py @@ -0,0 +1,60 @@ +_base_ = './fcos_r50_caffe_fpn_gn-head_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) +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=[(1333, 640), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + lr=0.01, paramwise_cfg=dict(bias_lr_mult=2., bias_decay_mult=0.)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/fcos/metafile.yml b/configs/fcos/metafile.yml new file mode 100644 index 0000000..ae922eb --- /dev/null +++ b/configs/fcos/metafile.yml @@ -0,0 +1,146 @@ +Collections: + - Name: FCOS + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - Group Normalization + - ResNet + Paper: + URL: https://arxiv.org/abs/1904.01355 + Title: 'FCOS: Fully Convolutional One-Stage Object Detection' + README: configs/fcos/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/fcos.py#L6 + Version: v2.0.0 + +Models: + - Name: fcos_r50_caffe_fpn_gn-head_1x_coco + In Collection: FCOS + Config: configs/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco.py + Metadata: + Training Memory (GB): 3.6 + inference time (ms/im): + - value: 44.05 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_1x_coco/fcos_r50_caffe_fpn_gn-head_1x_coco-821213aa.pth + + - Name: fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco + In Collection: FCOS + Config: configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco.py + Metadata: + Training Memory (GB): 3.7 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_1x_coco-0a0d75a8.pth + + - Name: fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco + In Collection: FCOS + Config: configs/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco.py + Metadata: + Training Memory (GB): 3.8 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco/fcos_center-normbbox-centeronreg-giou_r50_caffe_fpn_gn-head_dcn_1x_coco-ae4d8b3d.pth + + - Name: fcos_r101_caffe_fpn_gn-head_1x_coco + In Collection: FCOS + Config: configs/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco.py + Metadata: + Training Memory (GB): 5.5 + inference time (ms/im): + - value: 57.8 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r101_caffe_fpn_gn-head_1x_coco/fcos_r101_caffe_fpn_gn-head_1x_coco-0e37b982.pth + + - Name: fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco + In Collection: FCOS + Config: configs/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py + Metadata: + Training Memory (GB): 2.6 + inference time (ms/im): + - value: 43.67 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco/fcos_r50_caffe_fpn_gn-head_mstrain_640-800_2x_coco-d92ceeea.pth + + - Name: fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco + In Collection: FCOS + Config: configs/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco.py + Metadata: + Training Memory (GB): 5.5 + inference time (ms/im): + - value: 57.8 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco/fcos_r101_caffe_fpn_gn-head_mstrain_640-800_2x_coco-511424d6.pth + + - Name: fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco + In Collection: FCOS + Config: configs/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco.py + Metadata: + Training Memory (GB): 10.0 + inference time (ms/im): + - value: 103.09 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco-ede514a8.pth diff --git a/configs/foveabox/README.md b/configs/foveabox/README.md new file mode 100644 index 0000000..b9b5684 --- /dev/null +++ b/configs/foveabox/README.md @@ -0,0 +1,41 @@ +# FoveaBox: Beyond Anchor-based Object Detector + + + +FoveaBox is an accurate, flexible and completely anchor-free object detection system for object detection framework, as presented in our paper [https://arxiv.org/abs/1904.03797](https://arxiv.org/abs/1904.03797): +Different from previous anchor-based methods, FoveaBox directly learns the object existing possibility and the bounding box coordinates without anchor reference. This is achieved by: (a) predicting category-sensitive semantic maps for the object existing possibility, and (b) producing category-agnostic bounding box for each position that potentially contains an object. + +## Main Results + +### Results on R50/101-FPN + +| Backbone | Style | align | ms-train| Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | pytorch | N | N | 1x | 5.6 | 24.1 | 36.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r50_fpn_4x4_1x_coco/fovea_r50_fpn_4x4_1x_coco_20200219-ee4d5303.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r50_fpn_4x4_1x_coco/fovea_r50_fpn_4x4_1x_coco_20200219_223025.log.json) | +| R-50 | pytorch | N | N | 2x | 5.6 | - | 37.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r50_fpn_4x4_2x_coco/fovea_r50_fpn_4x4_2x_coco_20200203-2df792b1.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r50_fpn_4x4_2x_coco/fovea_r50_fpn_4x4_2x_coco_20200203_112043.log.json) | +| R-50 | pytorch | Y | N | 2x | 8.1 | 19.4 | 37.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco/fovea_align_r50_fpn_gn-head_4x4_2x_coco_20200203-8987880d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco/fovea_align_r50_fpn_gn-head_4x4_2x_coco_20200203_134252.log.json) | +| R-50 | pytorch | Y | Y | 2x | 8.1 | 18.3 | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco_20200205-85ce26cb.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco_20200205_112557.log.json) | +| R-101 | pytorch | N | N | 1x | 9.2 | 17.4 | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_r101_fpn_4x4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r101_fpn_4x4_1x_coco/fovea_r101_fpn_4x4_1x_coco_20200219-05e38f1c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r101_fpn_4x4_1x_coco/fovea_r101_fpn_4x4_1x_coco_20200219_011740.log.json) | +| R-101 | pytorch | N | N | 2x | 11.7 | - | 40.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_r101_fpn_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r101_fpn_4x4_2x_coco/fovea_r101_fpn_4x4_2x_coco_20200208-02320ea4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r101_fpn_4x4_2x_coco/fovea_r101_fpn_4x4_2x_coco_20200208_202059.log.json) | +| R-101 | pytorch | Y | N | 2x | 11.7 | 14.7 | 40.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco/fovea_align_r101_fpn_gn-head_4x4_2x_coco_20200208-c39a027a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco/fovea_align_r101_fpn_gn-head_4x4_2x_coco_20200208_203337.log.json) | +| R-101 | pytorch | Y | Y | 2x | 11.7 | 14.7 | 42.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco_20200208-649c5eb6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco_20200208_202124.log.json) | + +[1] *1x and 2x mean the model is trained for 12 and 24 epochs, respectively.* \ +[2] *Align means utilizing deformable convolution to align the cls branch.* \ +[3] *All results are obtained with a single model and without any test time data augmentation.*\ +[4] *We use 4 GPUs for training.* + +Any pull requests or issues are welcome. + +## Citations + +Please consider citing our paper in your publications if the project helps your research. BibTeX reference is as follows. + +```latex +@article{kong2019foveabox, + title={FoveaBox: Beyond Anchor-based Object Detector}, + author={Kong, Tao and Sun, Fuchun and Liu, Huaping and Jiang, Yuning and Shi, Jianbo}, + journal={arXiv preprint arXiv:1904.03797}, + year={2019} +} +``` diff --git a/configs/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco.py b/configs/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco.py new file mode 100644 index 0000000..c5d1784 --- /dev/null +++ b/configs/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco.py @@ -0,0 +1,12 @@ +_base_ = './fovea_r50_fpn_4x4_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101')), + bbox_head=dict( + with_deform=True, + norm_cfg=dict(type='GN', num_groups=32, requires_grad=True))) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py b/configs/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py new file mode 100644 index 0000000..cc5affe --- /dev/null +++ b/configs/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py @@ -0,0 +1,29 @@ +_base_ = './fovea_r50_fpn_4x4_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101')), + bbox_head=dict( + with_deform=True, + norm_cfg=dict(type='GN', num_groups=32, requires_grad=True))) +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=[(1333, 640), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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']), +] +data = dict(train=dict(pipeline=train_pipeline)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco.py b/configs/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco.py new file mode 100644 index 0000000..e7265bc --- /dev/null +++ b/configs/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco.py @@ -0,0 +1,10 @@ +_base_ = './fovea_r50_fpn_4x4_1x_coco.py' +model = dict( + bbox_head=dict( + with_deform=True, + norm_cfg=dict(type='GN', num_groups=32, requires_grad=True))) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py b/configs/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py new file mode 100644 index 0000000..8fc39be --- /dev/null +++ b/configs/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py @@ -0,0 +1,25 @@ +_base_ = './fovea_r50_fpn_4x4_1x_coco.py' +model = dict( + bbox_head=dict( + with_deform=True, + norm_cfg=dict(type='GN', num_groups=32, requires_grad=True))) +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=[(1333, 640), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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']), +] +data = dict(train=dict(pipeline=train_pipeline)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/foveabox/fovea_r101_fpn_4x4_1x_coco.py b/configs/foveabox/fovea_r101_fpn_4x4_1x_coco.py new file mode 100644 index 0000000..9201af1 --- /dev/null +++ b/configs/foveabox/fovea_r101_fpn_4x4_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './fovea_r50_fpn_4x4_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/foveabox/fovea_r101_fpn_4x4_2x_coco.py b/configs/foveabox/fovea_r101_fpn_4x4_2x_coco.py new file mode 100644 index 0000000..1ef5243 --- /dev/null +++ b/configs/foveabox/fovea_r101_fpn_4x4_2x_coco.py @@ -0,0 +1,6 @@ +_base_ = './fovea_r50_fpn_4x4_2x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py b/configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py new file mode 100644 index 0000000..7e986eb --- /dev/null +++ b/configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py @@ -0,0 +1,52 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# model settings +model = dict( + type='FOVEA', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + num_outs=5, + add_extra_convs='on_input'), + bbox_head=dict( + type='FoveaHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + strides=[8, 16, 32, 64, 128], + base_edge_list=[16, 32, 64, 128, 256], + scale_ranges=((1, 64), (32, 128), (64, 256), (128, 512), (256, 2048)), + sigma=0.4, + with_deform=False, + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=1.50, + alpha=0.4, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0)), + # training and testing settings + train_cfg=dict(), + test_cfg=dict( + nms_pre=1000, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100)) +data = dict(samples_per_gpu=4, workers_per_gpu=4) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py b/configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py new file mode 100644 index 0000000..68ce4d2 --- /dev/null +++ b/configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './fovea_r50_fpn_4x4_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/foveabox/metafile.yml b/configs/foveabox/metafile.yml new file mode 100644 index 0000000..fe9a283 --- /dev/null +++ b/configs/foveabox/metafile.yml @@ -0,0 +1,172 @@ +Collections: + - Name: FoveaBox + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 4x V100 GPUs + Architecture: + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/1904.03797 + Title: 'FoveaBox: Beyond Anchor-based Object Detector' + README: configs/foveabox/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/fovea.py#L6 + Version: v2.0.0 + +Models: + - Name: fovea_r50_fpn_4x4_1x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_r50_fpn_4x4_1x_coco.py + Metadata: + Training Memory (GB): 5.6 + inference time (ms/im): + - value: 41.49 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r50_fpn_4x4_1x_coco/fovea_r50_fpn_4x4_1x_coco_20200219-ee4d5303.pth + + - Name: fovea_r50_fpn_4x4_2x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_r50_fpn_4x4_2x_coco.py + Metadata: + Training Memory (GB): 5.6 + inference time (ms/im): + - value: 41.49 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r50_fpn_4x4_2x_coco/fovea_r50_fpn_4x4_2x_coco_20200203-2df792b1.pth + + - Name: fovea_align_r50_fpn_gn-head_4x4_2x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco.py + Metadata: + Training Memory (GB): 8.1 + inference time (ms/im): + - value: 51.55 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r50_fpn_gn-head_4x4_2x_coco/fovea_align_r50_fpn_gn-head_4x4_2x_coco_20200203-8987880d.pth + + - Name: fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py + Metadata: + Training Memory (GB): 8.1 + inference time (ms/im): + - value: 54.64 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco/fovea_align_r50_fpn_gn-head_mstrain_640-800_4x4_2x_coco_20200205-85ce26cb.pth + + - Name: fovea_r101_fpn_4x4_1x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_r101_fpn_4x4_1x_coco.py + Metadata: + Training Memory (GB): 9.2 + inference time (ms/im): + - value: 57.47 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r101_fpn_4x4_1x_coco/fovea_r101_fpn_4x4_1x_coco_20200219-05e38f1c.pth + + - Name: fovea_r101_fpn_4x4_2x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_r101_fpn_4x4_2x_coco.py + Metadata: + Training Memory (GB): 11.7 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_r101_fpn_4x4_2x_coco/fovea_r101_fpn_4x4_2x_coco_20200208-02320ea4.pth + + - Name: fovea_align_r101_fpn_gn-head_4x4_2x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco.py + Metadata: + Training Memory (GB): 11.7 + inference time (ms/im): + - value: 68.03 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r101_fpn_gn-head_4x4_2x_coco/fovea_align_r101_fpn_gn-head_4x4_2x_coco_20200208-c39a027a.pth + + - Name: fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco + In Collection: FoveaBox + Config: configs/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco.py + Metadata: + Training Memory (GB): 11.7 + inference time (ms/im): + - value: 68.03 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/foveabox/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco/fovea_align_r101_fpn_gn-head_mstrain_640-800_4x4_2x_coco_20200208-649c5eb6.pth diff --git a/configs/fp16/README.md b/configs/fp16/README.md new file mode 100644 index 0000000..171aa1b --- /dev/null +++ b/configs/fp16/README.md @@ -0,0 +1,24 @@ +# Mixed Precision Training + +## Introduction + + + +```latex +@article{micikevicius2017mixed, + title={Mixed precision training}, + author={Micikevicius, Paulius and Narang, Sharan and Alben, Jonah and Diamos, Gregory and Elsen, Erich and Garcia, David and Ginsburg, Boris and Houston, Michael and Kuchaiev, Oleksii and Venkatesh, Ganesh and others}, + journal={arXiv preprint arXiv:1710.03740}, + year={2017} +} +``` + +## Results and Models + +| Architecture | Backbone | Style | Conv | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:------------:|:---------:|:-------:|:------------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| Faster R-CNN | R-50 | pytorch | - | 1x | 3.4 | 28.8 | 37.5 | - |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fp16/faster_rcnn_r50_fpn_fp16_1x_coco/faster_rcnn_r50_fpn_fp16_1x_coco_20200204-d4dc1471.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fp16/faster_rcnn_r50_fpn_fp16_1x_coco/faster_rcnn_r50_fpn_fp16_1x_coco_20200204_143530.log.json) | +| Mask R-CNN | R-50 | pytorch | - | 1x | 3.6 | 24.1 | 38.1 | 34.7 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_1x_coco/mask_rcnn_r50_fpn_fp16_1x_coco_20200205-59faf7e4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_1x_coco/mask_rcnn_r50_fpn_fp16_1x_coco_20200205_130539.log.json) | +| Mask R-CNN | R-50 | pytorch | dconv(c3-c5) | 1x | 3.0 | | 41.9 | 37.5 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco_20210520_180247-c06429d2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco_20210520_180247.log.json) | +| Mask R-CNN | R-50 | pytorch | mdconv(c3-c5)| 1x | 3.1 | | 42.0 | 37.6 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco_20210520_180434-cf8fefa5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco_20210520_180434.log.json) | +| Retinanet | R-50 | pytorch | - | 1x | 2.8 | 31.6 | 36.4 | |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fp16/retinanet_r50_fpn_fp16_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fp16/retinanet_r50_fpn_fp16_1x_coco/retinanet_r50_fpn_fp16_1x_coco_20200702-0dbfb212.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fp16/retinanet_r50_fpn_fp16_1x_coco/retinanet_r50_fpn_fp16_1x_coco_20200702_020127.log.json) | diff --git a/configs/fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py b/configs/fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py new file mode 100644 index 0000000..78fa5b6 --- /dev/null +++ b/configs/fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py @@ -0,0 +1,3 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +# fp16 settings +fp16 = dict(loss_scale=512.) diff --git a/configs/fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py b/configs/fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py new file mode 100644 index 0000000..f506ea8 --- /dev/null +++ b/configs/fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py @@ -0,0 +1,3 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +# fp16 settings +fp16 = dict(loss_scale=512.) diff --git a/configs/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py b/configs/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..ee5cca7 --- /dev/null +++ b/configs/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) + +fp16 = dict(loss_scale=512.) diff --git a/configs/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py b/configs/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..7e21454 --- /dev/null +++ b/configs/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCNv2', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True))) + +fp16 = dict(loss_scale=512.) diff --git a/configs/fp16/metafile.yml b/configs/fp16/metafile.yml new file mode 100644 index 0000000..70d6649 --- /dev/null +++ b/configs/fp16/metafile.yml @@ -0,0 +1,113 @@ +Collections: + - Name: FP16 + Metadata: + Training Data: COCO + Training Techniques: + - Mixed Precision Training + Training Resources: 8x V100 GPUs + Paper: + URL: https://arxiv.org/abs/1710.03740 + Title: 'Mixed Precision Training' + README: configs/fp16/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/core/fp16/hooks.py#L11 + Version: v2.0.0 + +Models: + - Name: faster_rcnn_r50_fpn_fp16_1x_coco + In Collection: FP16 + Config: configs/fp16/faster_rcnn_r50_fpn_fp16_1x_coco.py + Metadata: + Training Memory (GB): 3.4 + inference time (ms/im): + - value: 34.72 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP16 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fp16/faster_rcnn_r50_fpn_fp16_1x_coco/faster_rcnn_r50_fpn_fp16_1x_coco_20200204-d4dc1471.pth + + - Name: mask_rcnn_r50_fpn_fp16_1x_coco + In Collection: FP16 + Config: configs/fp16/mask_rcnn_r50_fpn_fp16_1x_coco.py + Metadata: + Training Memory (GB): 3.6 + inference time (ms/im): + - value: 41.49 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP16 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 34.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_1x_coco/mask_rcnn_r50_fpn_fp16_1x_coco_20200205-59faf7e4.pth + + - Name: mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco + In Collection: FP16 + Config: configs/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 3.0 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_fp16_dconv_c3-c5_1x_coco_20210520_180247-c06429d2.pth + + - Name: mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco + In Collection: FP16 + Config: configs/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 3.1 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fp16/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco/mask_rcnn_r50_fpn_fp16_mdconv_c3-c5_1x_coco_20210520_180434-cf8fefa5.pth + + - Name: retinanet_r50_fpn_fp16_1x_coco + In Collection: FP16 + Config: configs/fp16/retinanet_r50_fpn_fp16_1x_coco.py + Metadata: + Training Memory (GB): 2.8 + inference time (ms/im): + - value: 31.65 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP16 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fp16/retinanet_r50_fpn_fp16_1x_coco/retinanet_r50_fpn_fp16_1x_coco_20200702-0dbfb212.pth diff --git a/configs/fp16/retinanet_r50_fpn_fp16_1x_coco.py b/configs/fp16/retinanet_r50_fpn_fp16_1x_coco.py new file mode 100644 index 0000000..519c4db --- /dev/null +++ b/configs/fp16/retinanet_r50_fpn_fp16_1x_coco.py @@ -0,0 +1,3 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' +# fp16 settings +fp16 = dict(loss_scale=512.) diff --git a/configs/fpg/README.md b/configs/fpg/README.md new file mode 100644 index 0000000..c0545da --- /dev/null +++ b/configs/fpg/README.md @@ -0,0 +1,30 @@ +# Feature Pyramid Grids + + +## Introduction + +```latex +@article{chen2020feature, + title={Feature pyramid grids}, + author={Chen, Kai and Cao, Yuhang and Loy, Chen Change and Lin, Dahua and Feichtenhofer, Christoph}, + journal={arXiv preprint arXiv:2004.03580}, + year={2020} +} +``` + +## Results and Models + +We benchmark the new training schedule (crop training, large batch, unfrozen BN, 50 epochs) introduced in NAS-FPN. +All backbones are Resnet-50 in pytorch style. + +| Method | Neck | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:------------:|:-----------:|:-------:|:--------:|:--------------:|:------:|:-------:|:-------:|:--------:| +| Faster R-CNN | FPG | 50e | 20.0 | - | 42.2 | - |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fpg/faster_rcnn_r50_fpg_crop640_50e_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/fpg/faster_rcnn_r50_fpg_crop640_50e_coco/faster_rcnn_r50_fpg_crop640_50e_coco-76220505.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fpg/faster_rcnn_r50_fpg_crop640_50e_coco/20210218_223520.log.json) | +| Faster R-CNN | FPG-chn128 | 50e | 11.9 | - | 41.2 | - |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco/faster_rcnn_r50_fpg-chn128_crop640_50e_coco-24257de9.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco/20210218_221412.log.json) | +| Mask R-CNN | FPG | 50e | 23.2 | - | 42.7 | 37.8 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/fpg/mask_rcnn_r50_fpg_crop640_50e_coco/mask_rcnn_r50_fpg_crop640_50e_coco-c5860453.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fpg/mask_rcnn_r50_fpg_crop640_50e_coco/20210222_205447.log.json) | +| Mask R-CNN | FPG-chn128 | 50e | 15.3 | - | 41.7 | 36.9 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco/mask_rcnn_r50_fpg-chn128_crop640_50e_coco-5c6ea10d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco/20210223_025039.log.json) | +| RetinaNet | FPG | 50e | 20.8 | - | 40.5 | - |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fpg/retinanet_r50_fpg_crop640_50e_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/fpg/retinanet_r50_fpg_crop640_50e_coco/retinanet_r50_fpg_crop640_50e_coco-46fdd1c6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fpg/retinanet_r50_fpg_crop640_50e_coco/20210225_143957.log.json) | +| RetinaNet | FPG-chn128 | 50e | 19.9 | - | 40.3 | - |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco/retinanet_r50_fpg-chn128_crop640_50e_coco-5cf33c76.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco/20210225_184328.log.json) | + +**Note**: Chn128 means to decrease the number of channels of features and convs from 256 (default) to 128 in +Neck and BBox Head, which can greatly decrease memory consumption without sacrificing much precision. diff --git a/configs/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco.py b/configs/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco.py new file mode 100644 index 0000000..4535034 --- /dev/null +++ b/configs/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco.py @@ -0,0 +1,9 @@ +_base_ = 'faster_rcnn_r50_fpg_crop640_50e_coco.py' + +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + neck=dict(out_channels=128, inter_channels=128), + rpn_head=dict(in_channels=128), + roi_head=dict( + bbox_roi_extractor=dict(out_channels=128), + bbox_head=dict(in_channels=128))) diff --git a/configs/fpg/faster_rcnn_r50_fpg_crop640_50e_coco.py b/configs/fpg/faster_rcnn_r50_fpg_crop640_50e_coco.py new file mode 100644 index 0000000..3ab2a2c --- /dev/null +++ b/configs/fpg/faster_rcnn_r50_fpg_crop640_50e_coco.py @@ -0,0 +1,48 @@ +_base_ = 'faster_rcnn_r50_fpn_crop640_50e_coco.py' + +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + neck=dict( + type='FPG', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + inter_channels=256, + num_outs=5, + stack_times=9, + paths=['bu'] * 9, + same_down_trans=None, + same_up_trans=dict( + type='conv', + kernel_size=3, + stride=2, + padding=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + across_lateral_trans=dict( + type='conv', + kernel_size=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + across_down_trans=dict( + type='interpolation_conv', + mode='nearest', + kernel_size=3, + norm_cfg=norm_cfg, + order=('act', 'conv', 'norm'), + inplace=False), + across_up_trans=None, + across_skip_trans=dict( + type='conv', + kernel_size=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + output_trans=dict( + type='last_conv', + kernel_size=3, + order=('act', 'conv', 'norm'), + inplace=False), + norm_cfg=norm_cfg, + skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()])) diff --git a/configs/fpg/faster_rcnn_r50_fpn_crop640_50e_coco.py b/configs/fpg/faster_rcnn_r50_fpn_crop640_50e_coco.py new file mode 100644 index 0000000..95f4e91 --- /dev/null +++ b/configs/fpg/faster_rcnn_r50_fpn_crop640_50e_coco.py @@ -0,0 +1,68 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + backbone=dict(norm_cfg=norm_cfg, norm_eval=False), + neck=dict(norm_cfg=norm_cfg), + roi_head=dict(bbox_head=dict(norm_cfg=norm_cfg))) +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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=(640, 640), + ratio_range=(0.8, 1.2), + keep_ratio=True), + dict(type='RandomCrop', crop_size=(640, 640)), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size=(640, 640)), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(640, 640), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=8, + workers_per_gpu=4, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# learning policy +optimizer = dict( + type='SGD', + lr=0.08, + momentum=0.9, + weight_decay=0.0001, + paramwise_cfg=dict(norm_decay_mult=0, bypass_duplicate=True)) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=1000, + warmup_ratio=0.1, + step=[30, 40]) +# runtime settings +runner = dict(max_epochs=50) +evaluation = dict(interval=2) diff --git a/configs/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco.py b/configs/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco.py new file mode 100644 index 0000000..baa4a5a --- /dev/null +++ b/configs/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco.py @@ -0,0 +1,10 @@ +_base_ = 'mask_rcnn_r50_fpg_crop640_50e_coco.py' + +model = dict( + neck=dict(out_channels=128, inter_channels=128), + rpn_head=dict(in_channels=128), + roi_head=dict( + bbox_roi_extractor=dict(out_channels=128), + bbox_head=dict(in_channels=128), + mask_roi_extractor=dict(out_channels=128), + mask_head=dict(in_channels=128))) diff --git a/configs/fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py b/configs/fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py new file mode 100644 index 0000000..3c9ea27 --- /dev/null +++ b/configs/fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py @@ -0,0 +1,48 @@ +_base_ = 'mask_rcnn_r50_fpn_crop640_50e_coco.py' + +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + neck=dict( + type='FPG', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + inter_channels=256, + num_outs=5, + stack_times=9, + paths=['bu'] * 9, + same_down_trans=None, + same_up_trans=dict( + type='conv', + kernel_size=3, + stride=2, + padding=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + across_lateral_trans=dict( + type='conv', + kernel_size=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + across_down_trans=dict( + type='interpolation_conv', + mode='nearest', + kernel_size=3, + norm_cfg=norm_cfg, + order=('act', 'conv', 'norm'), + inplace=False), + across_up_trans=None, + across_skip_trans=dict( + type='conv', + kernel_size=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + output_trans=dict( + type='last_conv', + kernel_size=3, + order=('act', 'conv', 'norm'), + inplace=False), + norm_cfg=norm_cfg, + skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()])) diff --git a/configs/fpg/mask_rcnn_r50_fpn_crop640_50e_coco.py b/configs/fpg/mask_rcnn_r50_fpn_crop640_50e_coco.py new file mode 100644 index 0000000..8dfdbb4 --- /dev/null +++ b/configs/fpg/mask_rcnn_r50_fpn_crop640_50e_coco.py @@ -0,0 +1,74 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + backbone=dict(norm_cfg=norm_cfg, norm_eval=False), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + norm_cfg=norm_cfg, + num_outs=5), + roi_head=dict( + bbox_head=dict(norm_cfg=norm_cfg), mask_head=dict(norm_cfg=norm_cfg))) +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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=(640, 640), + ratio_range=(0.8, 1.2), + keep_ratio=True), + dict(type='RandomCrop', crop_size=(640, 640)), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size=(640, 640)), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(640, 640), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=8, + workers_per_gpu=4, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# learning policy +optimizer = dict( + type='SGD', + lr=0.08, + momentum=0.9, + weight_decay=0.0001, + paramwise_cfg=dict(norm_decay_mult=0, bypass_duplicate=True)) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=1000, + warmup_ratio=0.1, + step=[30, 40]) +# runtime settings +runner = dict(max_epochs=50) +evaluation = dict(interval=2) diff --git a/configs/fpg/metafile.yml b/configs/fpg/metafile.yml new file mode 100644 index 0000000..885d857 --- /dev/null +++ b/configs/fpg/metafile.yml @@ -0,0 +1,104 @@ +Collections: + - Name: Feature Pyramid Grids + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Feature Pyramid Grids + Paper: + URL: https://arxiv.org/abs/2004.03580 + Title: 'Feature Pyramid Grids' + README: configs/fpg/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.10.0/mmdet/models/necks/fpg.py#L101 + Version: v2.10.0 + +Models: + - Name: faster_rcnn_r50_fpg_crop640_50e_coco + In Collection: Feature Pyramid Grids + Config: configs/fpg/faster_rcnn_r50_fpg_crop640_50e_coco.py + Metadata: + Training Memory (GB): 20.0 + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fpg/faster_rcnn_r50_fpg_crop640_50e_coco/faster_rcnn_r50_fpg_crop640_50e_coco-76220505.pth + + - Name: faster_rcnn_r50_fpg-chn128_crop640_50e_coco + In Collection: Feature Pyramid Grids + Config: configs/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco.py + Metadata: + Training Memory (GB): 11.9 + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fpg/faster_rcnn_r50_fpg-chn128_crop640_50e_coco/faster_rcnn_r50_fpg-chn128_crop640_50e_coco-24257de9.pth + + - Name: mask_rcnn_r50_fpg_crop640_50e_coco + In Collection: Feature Pyramid Grids + Config: configs/fpg/mask_rcnn_r50_fpg_crop640_50e_coco.py + Metadata: + Training Memory (GB): 23.2 + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fpg/mask_rcnn_r50_fpg_crop640_50e_coco/mask_rcnn_r50_fpg_crop640_50e_coco-c5860453.pth + + - Name: mask_rcnn_r50_fpg-chn128_crop640_50e_coco + In Collection: Feature Pyramid Grids + Config: configs/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco.py + Metadata: + Training Memory (GB): 15.3 + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fpg/mask_rcnn_r50_fpg-chn128_crop640_50e_coco/mask_rcnn_r50_fpg-chn128_crop640_50e_coco-5c6ea10d.pth + + - Name: retinanet_r50_fpg_crop640_50e_coco + In Collection: Feature Pyramid Grids + Config: configs/fpg/retinanet_r50_fpg_crop640_50e_coco.py + Metadata: + Training Memory (GB): 20.8 + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fpg/retinanet_r50_fpg_crop640_50e_coco/retinanet_r50_fpg_crop640_50e_coco-46fdd1c6.pth + + - Name: retinanet_r50_fpg-chn128_crop640_50e_coco + In Collection: Feature Pyramid Grids + Config: configs/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco.py + Metadata: + Training Memory (GB): 19.9 + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco/retinanet_r50_fpg-chn128_crop640_50e_coco-5cf33c76.pth diff --git a/configs/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco.py b/configs/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco.py new file mode 100644 index 0000000..9a6cf7e --- /dev/null +++ b/configs/fpg/retinanet_r50_fpg-chn128_crop640_50e_coco.py @@ -0,0 +1,5 @@ +_base_ = 'retinanet_r50_fpg_crop640_50e_coco.py' + +model = dict( + neck=dict(out_channels=128, inter_channels=128), + bbox_head=dict(in_channels=128)) diff --git a/configs/fpg/retinanet_r50_fpg_crop640_50e_coco.py b/configs/fpg/retinanet_r50_fpg_crop640_50e_coco.py new file mode 100644 index 0000000..504ed5e --- /dev/null +++ b/configs/fpg/retinanet_r50_fpg_crop640_50e_coco.py @@ -0,0 +1,53 @@ +_base_ = '../nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py' + +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + neck=dict( + _delete_=True, + type='FPG', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + inter_channels=256, + num_outs=5, + add_extra_convs=True, + start_level=1, + stack_times=9, + paths=['bu'] * 9, + same_down_trans=None, + same_up_trans=dict( + type='conv', + kernel_size=3, + stride=2, + padding=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + across_lateral_trans=dict( + type='conv', + kernel_size=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + across_down_trans=dict( + type='interpolation_conv', + mode='nearest', + kernel_size=3, + norm_cfg=norm_cfg, + order=('act', 'conv', 'norm'), + inplace=False), + across_up_trans=None, + across_skip_trans=dict( + type='conv', + kernel_size=1, + norm_cfg=norm_cfg, + inplace=False, + order=('act', 'conv', 'norm')), + output_trans=dict( + type='last_conv', + kernel_size=3, + order=('act', 'conv', 'norm'), + inplace=False), + norm_cfg=norm_cfg, + skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()])) + +evaluation = dict(interval=2) diff --git a/configs/free_anchor/README.md b/configs/free_anchor/README.md new file mode 100644 index 0000000..5014bc0 --- /dev/null +++ b/configs/free_anchor/README.md @@ -0,0 +1,27 @@ +# FreeAnchor: Learning to Match Anchors for Visual Object Detection + +## Introduction + + + +```latex +@inproceedings{zhang2019freeanchor, + title = {{FreeAnchor}: Learning to Match Anchors for Visual Object Detection}, + author = {Zhang, Xiaosong and Wan, Fang and Liu, Chang and Ji, Rongrong and Ye, Qixiang}, + booktitle = {Neural Information Processing Systems}, + year = {2019} +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:--------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | pytorch | 1x | 4.9 | 18.4 | 38.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco/retinanet_free_anchor_r50_fpn_1x_coco_20200130-0f67375f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco/retinanet_free_anchor_r50_fpn_1x_coco_20200130_095625.log.json) | +| R-101 | pytorch | 1x | 6.8 | 14.9 | 40.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco/retinanet_free_anchor_r101_fpn_1x_coco_20200130-358324e6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco/retinanet_free_anchor_r101_fpn_1x_coco_20200130_100723.log.json) | +| X-101-32x4d | pytorch | 1x | 8.1 | 11.1 | 41.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco/retinanet_free_anchor_x101_32x4d_fpn_1x_coco_20200130-d4846968.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco/retinanet_free_anchor_x101_32x4d_fpn_1x_coco_20200130_095627.log.json) | + +**Notes:** + +- We use 8 GPUs with 2 images/GPU. +- For more settings and models, please refer to the [official repo](https://github.com/zhangxiaosong18/FreeAnchor). diff --git a/configs/free_anchor/metafile.yml b/configs/free_anchor/metafile.yml new file mode 100644 index 0000000..170fb5c --- /dev/null +++ b/configs/free_anchor/metafile.yml @@ -0,0 +1,79 @@ +Collections: + - Name: FreeAnchor + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FreeAnchor + - ResNet + Paper: + URL: https://arxiv.org/abs/1909.02466 + Title: 'FreeAnchor: Learning to Match Anchors for Visual Object Detection' + README: configs/free_anchor/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/dense_heads/free_anchor_retina_head.py#L10 + Version: v2.0.0 + +Models: + - Name: retinanet_free_anchor_r50_fpn_1x_coco + In Collection: FreeAnchor + Config: configs/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.9 + inference time (ms/im): + - value: 54.35 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco/retinanet_free_anchor_r50_fpn_1x_coco_20200130-0f67375f.pth + + - Name: retinanet_free_anchor_r101_fpn_1x_coco + In Collection: FreeAnchor + Config: configs/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.8 + inference time (ms/im): + - value: 67.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco/retinanet_free_anchor_r101_fpn_1x_coco_20200130-358324e6.pth + + - Name: retinanet_free_anchor_x101_32x4d_fpn_1x_coco + In Collection: FreeAnchor + Config: configs/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 8.1 + inference time (ms/im): + - value: 90.09 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco/retinanet_free_anchor_x101_32x4d_fpn_1x_coco_20200130-d4846968.pth diff --git a/configs/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco.py b/configs/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco.py new file mode 100644 index 0000000..f4aea53 --- /dev/null +++ b/configs/free_anchor/retinanet_free_anchor_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './retinanet_free_anchor_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco.py b/configs/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco.py new file mode 100644 index 0000000..28f983c --- /dev/null +++ b/configs/free_anchor/retinanet_free_anchor_r50_fpn_1x_coco.py @@ -0,0 +1,22 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' +model = dict( + bbox_head=dict( + _delete_=True, + type='FreeAnchorRetinaHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=4, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[8, 16, 32, 64, 128]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.1, 0.1, 0.2, 0.2]), + loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=0.75))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco.py b/configs/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..65f8a9e --- /dev/null +++ b/configs/free_anchor/retinanet_free_anchor_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,13 @@ +_base_ = './retinanet_free_anchor_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/fsaf/README.md b/configs/fsaf/README.md new file mode 100644 index 0000000..4d64392 --- /dev/null +++ b/configs/fsaf/README.md @@ -0,0 +1,45 @@ +# Feature Selective Anchor-Free Module for Single-Shot Object Detection + + + +FSAF is an anchor-free method published in CVPR2019 ([https://arxiv.org/pdf/1903.00621.pdf](https://arxiv.org/pdf/1903.00621.pdf)). +Actually it is equivalent to the anchor-based method with only one anchor at each feature map position in each FPN level. +And this is how we implemented it. +Only the anchor-free branch is released for its better compatibility with the current framework and less computational budget. + +In the original paper, feature maps within the central 0.2-0.5 area of a gt box are tagged as ignored. However, +it is empirically found that a hard threshold (0.2-0.2) gives a further gain on the performance. (see the table below) + +## Main Results + +### Results on R50/R101/X101-FPN + +| Backbone | ignore range | ms-train| Lr schd |Train Mem (GB)| Train time (s/iter) | Inf time (fps) | box AP | Config | Download | +|:----------:| :-------: |:-------:|:-------:|:------------:|:---------------:|:--------------:|:-------------:|:------:|:--------:| +| R-50 | 0.2-0.5 | N | 1x | 3.15 | 0.43 | 12.3 | 36.0 (35.9) | | [model](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_pscale0.2_nscale0.5_r50_fpn_1x_coco/fsaf_pscale0.2_nscale0.5_r50_fpn_1x_coco_20200715-b555b0e0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_pscale0.2_nscale0.5_r50_fpn_1x_coco/fsaf_pscale0.2_nscale0.5_r50_fpn_1x_coco_20200715_094657.log.json) | +| R-50 | 0.2-0.2 | N | 1x | 3.15 | 0.43 | 13.0 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf/fsaf_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r50_fpn_1x_coco/fsaf_r50_fpn_1x_coco-94ccc51f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r50_fpn_1x_coco/fsaf_r50_fpn_1x_coco_20200428_072327.log.json)| +| R-101 | 0.2-0.2 | N | 1x | 5.08 | 0.58 | 10.8 | 39.3 (37.9) | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf/fsaf_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r101_fpn_1x_coco/fsaf_r101_fpn_1x_coco-9e71098f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r101_fpn_1x_coco/fsaf_r101_fpn_1x_coco_20200428_160348.log.json)| +| X-101 | 0.2-0.2 | N | 1x | 9.38 | 1.23 | 5.6 | 42.4 (41.0) | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_x101_64x4d_fpn_1x_coco/fsaf_x101_64x4d_fpn_1x_coco-e3f6e6fd.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_x101_64x4d_fpn_1x_coco/fsaf_x101_64x4d_fpn_1x_coco_20200428_160424.log.json)| + +**Notes:** + +- *1x means the model is trained for 12 epochs.* +- *AP values in the brackets represent those reported in the original paper.* +- *All results are obtained with a single model and single-scale test.* +- *X-101 backbone represents ResNext-101-64x4d.* +- *All pretrained backbones use pytorch style.* +- *All models are trained on 8 Titan-XP gpus and tested on a single gpu.* + +## Citations + +BibTeX reference is as follows. + +```latex +@inproceedings{zhu2019feature, + title={Feature Selective Anchor-Free Module for Single-Shot Object Detection}, + author={Zhu, Chenchen and He, Yihui and Savvides, Marios}, + booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition}, + pages={840--849}, + year={2019} +} +``` diff --git a/configs/fsaf/fsaf_r101_fpn_1x_coco.py b/configs/fsaf/fsaf_r101_fpn_1x_coco.py new file mode 100644 index 0000000..12b49fe --- /dev/null +++ b/configs/fsaf/fsaf_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './fsaf_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/fsaf/fsaf_r50_fpn_1x_coco.py b/configs/fsaf/fsaf_r50_fpn_1x_coco.py new file mode 100644 index 0000000..67f3ec1 --- /dev/null +++ b/configs/fsaf/fsaf_r50_fpn_1x_coco.py @@ -0,0 +1,48 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' +# model settings +model = dict( + type='FSAF', + bbox_head=dict( + type='FSAFHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + reg_decoded_bbox=True, + # Only anchor-free branch is implemented. The anchor generator only + # generates 1 anchor at each feature point, as a substitute of the + # grid of features. + anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=1, + scales_per_octave=1, + ratios=[1.0], + strides=[8, 16, 32, 64, 128]), + bbox_coder=dict(_delete_=True, type='TBLRBBoxCoder', normalizer=4.0), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0, + reduction='none'), + loss_bbox=dict( + _delete_=True, + type='IoULoss', + eps=1e-6, + loss_weight=1.0, + reduction='none')), + # training and testing settings + train_cfg=dict( + assigner=dict( + _delete_=True, + type='CenterRegionAssigner', + pos_scale=0.2, + neg_scale=0.2, + min_pos_iof=0.01), + allowed_border=-1, + pos_weight=-1, + debug=False)) +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=10, norm_type=2)) diff --git a/configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py b/configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..89c0c63 --- /dev/null +++ b/configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './fsaf_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/fsaf/metafile.yml b/configs/fsaf/metafile.yml new file mode 100644 index 0000000..5434e9a --- /dev/null +++ b/configs/fsaf/metafile.yml @@ -0,0 +1,80 @@ +Collections: + - Name: FSAF + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x Titan-XP GPUs + Architecture: + - FPN + - FSAF + - ResNet + Paper: + URL: https://arxiv.org/abs/1903.00621 + Title: 'Feature Selective Anchor-Free Module for Single-Shot Object Detection' + README: configs/fsaf/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.1.0/mmdet/models/detectors/fsaf.py#L6 + Version: v2.1.0 + +Models: + - Name: fsaf_r50_fpn_1x_coco + In Collection: FSAF + Config: configs/fsaf/fsaf_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.15 + inference time (ms/im): + - value: 76.92 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r50_fpn_1x_coco/fsaf_r50_fpn_1x_coco-94ccc51f.pth + + - Name: fsaf_r101_fpn_1x_coco + In Collection: FSAF + Config: configs/fsaf/fsaf_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.08 + inference time (ms/im): + - value: 92.59 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.3 (37.9) + Weights: https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r101_fpn_1x_coco/fsaf_r101_fpn_1x_coco-9e71098f.pth + + - Name: fsaf_x101_64x4d_fpn_1x_coco + In Collection: FSAF + Config: configs/fsaf/fsaf_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 9.38 + inference time (ms/im): + - value: 178.57 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.4 (41.0) + Weights: https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_x101_64x4d_fpn_1x_coco/fsaf_x101_64x4d_fpn_1x_coco-e3f6e6fd.pth diff --git a/configs/gcnet/README.md b/configs/gcnet/README.md new file mode 100644 index 0000000..0ee6a94 --- /dev/null +++ b/configs/gcnet/README.md @@ -0,0 +1,59 @@ +# GCNet for Object Detection + +By [Yue Cao](http://yue-cao.me), [Jiarui Xu](http://jerryxu.net), [Stephen Lin](https://scholar.google.com/citations?user=c3PYmxUAAAAJ&hl=en), Fangyun Wei, [Han Hu](https://sites.google.com/site/hanhushomepage/). + +We provide config files to reproduce the results in the paper for +["GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond"](https://arxiv.org/abs/1904.11492) on COCO object detection. + +## Introduction + + + +**GCNet** is initially described in [arxiv](https://arxiv.org/abs/1904.11492). Via absorbing advantages of Non-Local Networks (NLNet) and Squeeze-Excitation Networks (SENet), GCNet provides a simple, fast and effective approach for global context modeling, which generally outperforms both NLNet and SENet on major benchmarks for various recognition tasks. + +## Citing GCNet + +```latex +@article{cao2019GCNet, + title={GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond}, + author={Cao, Yue and Xu, Jiarui and Lin, Stephen and Wei, Fangyun and Hu, Han}, + journal={arXiv preprint arXiv:1904.11492}, + year={2019} +} +``` + +## Results and models + +The results on COCO 2017val are shown in the below table. + +| Backbone | Model | Context | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------: | :--------------: | :------------: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| R-50-FPN | Mask | GC(c3-c5, r16) | 1x | 5.0 | | 39.7 | 35.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco_20200515_211915-187da160.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco_20200515_211915.log.json) | +| R-50-FPN | Mask | GC(c3-c5, r4) | 1x | 5.1 | 15.0 | 39.9 | 36.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204_024626.log.json) | +| R-101-FPN | Mask | GC(c3-c5, r16) | 1x | 7.6 | 11.4 | 41.3 | 37.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco_20200205-e58ae947.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco_20200205_192835.log.json) | +| R-101-FPN | Mask | GC(c3-c5, r4) | 1x | 7.8 | 11.6 | 42.2 | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco_20200206-af22dc9d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco_20200206_112128.log.json) | + +| Backbone | Model | Context | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------: | :--------------: | :------------: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :-------: | +| R-50-FPN | Mask | - | 1x | 4.4 | 16.6 | 38.4 | 34.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco_20200202-bb3eb55c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco_20200202_214122.log.json) | +| R-50-FPN | Mask | GC(c3-c5, r16) | 1x | 5.0 | 15.5 | 40.4 | 36.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200202-587b99aa.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200202_174907.log.json) | +| R-50-FPN | Mask | GC(c3-c5, r4) | 1x | 5.1 | 15.1 | 40.7 | 36.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200202-50b90e5c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200202_085547.log.json) | +| R-101-FPN | Mask | - | 1x | 6.4 | 13.3 | 40.5 | 36.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco_20200210-81658c8a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco_20200210_220422.log.json) | +| R-101-FPN | Mask | GC(c3-c5, r16) | 1x | 7.6 | 12.0 | 42.2 | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200207-945e77ca.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200207_015330.log.json) | +| R-101-FPN | Mask | GC(c3-c5, r4) | 1x | 7.8 | 11.8 | 42.2 | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200206-8407a3f0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200206_142508.log.json) | +| X-101-FPN | Mask | - | 1x | 7.6 | 11.3 | 42.4 | 37.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco_20200211-7584841c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco_20200211_054326.log.json) | +| X-101-FPN | Mask | GC(c3-c5, r16) | 1x | 8.8 | 9.8 | 43.5 | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200211-cbed3d2c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200211_164715.log.json) | +| X-101-FPN | Mask | GC(c3-c5, r4) | 1x | 9.0 | 9.7 | 43.9 | 39.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200212-68164964.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200212_070942.log.json) | +| X-101-FPN | Cascade Mask | - | 1x | 9.2 | 8.4 | 44.7 | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco_20200310-d5ad2a5e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco_20200310_115217.log.json) | +| X-101-FPN | Cascade Mask | GC(c3-c5, r16) | 1x | 10.3 | 7.7 | 46.2 | 39.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200211-10bf2463.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200211_184154.log.json) | +| X-101-FPN | Cascade Mask | GC(c3-c5, r4) | 1x | 10.6 | | 46.4 | 40.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200703_180653-ed035291.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200703_180653.log.json) | +| X-101-FPN | DCN Cascade Mask | - | 1x | | | 47.5 | 40.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco_20210615_211019-abbc39ea.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco_20210615_211019.log.json)| +| X-101-FPN | DCN Cascade Mask | GC(c3-c5, r16) | 1x | | | 48.0 | 41.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco_20210615_215648-44aa598a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco_20210615_215648.log.json) | +| X-101-FPN | DCN Cascade Mask | GC(c3-c5, r4) | 1x | | | 47.9 | 41.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco_20210615_161851-720338ec.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco_20210615_161851.log.json) | + +**Notes:** + +- The `SyncBN` is added in the backbone for all models in **Table 2**. +- `GC` denotes Global Context (GC) block is inserted after 1x1 conv of backbone. +- `DCN` denotes replace 3x3 conv with 3x3 Deformable Convolution in `c3-c5` stages of backbone. +- `r4` and `r16` denote ratio 4 and ratio 16 in GC block respectively. diff --git a/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py new file mode 100644 index 0000000..5118895 --- /dev/null +++ b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py @@ -0,0 +1,4 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False)) diff --git a/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..413499d --- /dev/null +++ b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py @@ -0,0 +1,4 @@ +_base_ = '../dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False)) diff --git a/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..50689aa --- /dev/null +++ b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..1367231 --- /dev/null +++ b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../dcn/cascade_mask_rcnn_x101_32x4d_fpn_dconv_c3-c5_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..50883ff --- /dev/null +++ b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..31fdd07 --- /dev/null +++ b/configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..ad6ad47 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = '../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict(plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..29f9167 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = '../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict(plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco.py b/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco.py new file mode 100644 index 0000000..6e1c5d0 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco.py @@ -0,0 +1,4 @@ +_base_ = '../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False)) diff --git a/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..781dba7 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..32972de --- /dev/null +++ b/configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..d299b69 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict(plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..5ac908e --- /dev/null +++ b/configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict(plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco.py b/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco.py new file mode 100644 index 0000000..0308a56 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco.py @@ -0,0 +1,4 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False)) diff --git a/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..e04780c --- /dev/null +++ b/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..980f819 --- /dev/null +++ b/configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py b/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py new file mode 100644 index 0000000..f0c96e5 --- /dev/null +++ b/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py @@ -0,0 +1,4 @@ +_base_ = '../mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), norm_eval=False)) diff --git a/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..7fb8e82 --- /dev/null +++ b/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 16), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py b/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py new file mode 100644 index 0000000..b1ddbee --- /dev/null +++ b/configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = '../mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(type='SyncBN', requires_grad=True), + norm_eval=False, + plugins=[ + dict( + cfg=dict(type='ContextBlock', ratio=1. / 4), + stages=(False, True, True, True), + position='after_conv3') + ])) diff --git a/configs/gcnet/metafile.yml b/configs/gcnet/metafile.yml new file mode 100644 index 0000000..1281122 --- /dev/null +++ b/configs/gcnet/metafile.yml @@ -0,0 +1,440 @@ +Collections: + - Name: GCNet + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Global Context Block + - FPN + - RPN + - ResNet + - ResNeXt + Paper: + URL: https://arxiv.org/abs/1904.11492 + Title: 'GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond' + README: configs/gcnet/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/ops/context_block.py#L13 + Version: v2.0.0 + +Models: + - Name: mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 5.0 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 35.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_r16_gcb_c3-c5_1x_coco_20200515_211915-187da160.pth + + - Name: mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 5.1 + inference time (ms/im): + - value: 66.67 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth + + - Name: mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 7.6 + inference time (ms/im): + - value: 87.72 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_r16_gcb_c3-c5_1x_coco_20200205-e58ae947.pth + + - Name: mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 7.8 + inference time (ms/im): + - value: 86.21 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_r4_gcb_c3-c5_1x_coco_20200206-af22dc9d.pth + + - Name: mask_rcnn_r50_fpn_syncbn-backbone_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco.py + Metadata: + Training Memory (GB): 4.4 + inference time (ms/im): + - value: 60.24 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 34.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_1x_coco_20200202-bb3eb55c.pth + + - Name: mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 5.0 + inference time (ms/im): + - value: 64.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200202-587b99aa.pth + + - Name: mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 5.1 + inference time (ms/im): + - value: 66.23 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200202-50b90e5c.pth + + - Name: mask_rcnn_r101_fpn_syncbn-backbone_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco.py + Metadata: + Training Memory (GB): 6.4 + inference time (ms/im): + - value: 75.19 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_1x_coco_20200210-81658c8a.pth + + - Name: mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 7.6 + inference time (ms/im): + - value: 83.33 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200207-945e77ca.pth + + - Name: mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 7.8 + inference time (ms/im): + - value: 84.75 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200206-8407a3f0.pth + + - Name: mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py + Metadata: + Training Memory (GB): 7.6 + inference time (ms/im): + - value: 88.5 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco_20200211-7584841c.pth + + - Name: mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 8.8 + inference time (ms/im): + - value: 102.04 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200211-cbed3d2c.pth + + - Name: mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 9.0 + inference time (ms/im): + - value: 103.09 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200212-68164964.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco + In Collection: GCNet + Config: configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco.py + Metadata: + Training Memory (GB): 9.2 + inference time (ms/im): + - value: 119.05 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_1x_coco_20200310-d5ad2a5e.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 10.3 + inference time (ms/im): + - value: 129.87 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r16_gcb_c3-c5_1x_coco_20200211-10bf2463.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 10.6 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200703_180653-ed035291.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_1x_coco_20210615_211019-abbc39ea.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 48.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 41.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r16_gcb_c3-c5_1x_coco_20210615_215648-44aa598a.pth + + - Name: cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco + In Collection: GCNet + Config: configs/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 41.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gcnet/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco/cascade_mask_rcnn_x101_32x4d_fpn_syncbn-backbone_dconv_c3-c5_r4_gcb_c3-c5_1x_coco_20210615_161851-720338ec.pth diff --git a/configs/gfl/README.md b/configs/gfl/README.md new file mode 100644 index 0000000..51a6aa1 --- /dev/null +++ b/configs/gfl/README.md @@ -0,0 +1,32 @@ +# Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection + +## Introduction + + + +We provide config files to reproduce the object detection results in the paper [Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection](https://arxiv.org/abs/2006.04388) + +```latex +@article{li2020generalized, + title={Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection}, + author={Li, Xiang and Wang, Wenhai and Wu, Lijun and Chen, Shuo and Hu, Xiaolin and Li, Jun and Tang, Jinhui and Yang, Jian}, + journal={arXiv preprint arXiv:2006.04388}, + year={2020} +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Multi-scale Training| Inf time (fps) | box AP | Config | Download | +|:-----------------:|:-------:|:-------:|:-------------------:|:--------------:|:------:|:------:|:--------:| +| R-50 | pytorch | 1x | No | 19.5 | 40.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_1x_coco/gfl_r50_fpn_1x_coco_20200629_121244-25944287.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_1x_coco/gfl_r50_fpn_1x_coco_20200629_121244.log.json) | +| R-50 | pytorch | 2x | Yes | 19.5 | 42.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_mstrain_2x_coco/gfl_r50_fpn_mstrain_2x_coco_20200629_213802-37bb1edc.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_mstrain_2x_coco/gfl_r50_fpn_mstrain_2x_coco_20200629_213802.log.json) | +| R-101 | pytorch | 2x | Yes | 14.7 | 44.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126.log.json) | +| R-101-dcnv2 | pytorch | 2x | Yes | 12.9 | 47.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco_20200630_102002-134b07df.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco_20200630_102002.log.json) | +| X-101-32x4d | pytorch | 2x | Yes | 12.1 | 45.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco/gfl_x101_32x4d_fpn_mstrain_2x_coco_20200630_102002-50c1ffdb.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco/gfl_x101_32x4d_fpn_mstrain_2x_coco_20200630_102002.log.json) | +| X-101-32x4d-dcnv2 | pytorch | 2x | Yes | 10.7 | 48.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco_20200630_102002-14a2bf25.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco_20200630_102002.log.json) | + +[1] *1x and 2x mean the model is trained for 90K and 180K iterations, respectively.* \ +[2] *All results are obtained with a single model and without any test time data augmentation such as multi-scale, flipping and etc..* \ +[3] *`dcnv2` denotes deformable convolutional networks v2.* \ +[4] *FPS is tested with a single GeForce RTX 2080Ti GPU, using a batch size of 1.* diff --git a/configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py b/configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py new file mode 100644 index 0000000..b72c2b6 --- /dev/null +++ b/configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py @@ -0,0 +1,15 @@ +_base_ = './gfl_r50_fpn_mstrain_2x_coco.py' +model = dict( + backbone=dict( + type='ResNet', + depth=101, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py b/configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py new file mode 100644 index 0000000..e33b5c0 --- /dev/null +++ b/configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py @@ -0,0 +1,13 @@ +_base_ = './gfl_r50_fpn_mstrain_2x_coco.py' +model = dict( + backbone=dict( + type='ResNet', + depth=101, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/gfl/gfl_r50_fpn_1x_coco.py b/configs/gfl/gfl_r50_fpn_1x_coco.py new file mode 100644 index 0000000..cfd4b02 --- /dev/null +++ b/configs/gfl/gfl_r50_fpn_1x_coco.py @@ -0,0 +1,57 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='GFL', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5), + bbox_head=dict( + type='GFLHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + octave_base_scale=8, + scales_per_octave=1, + strides=[8, 16, 32, 64, 128]), + loss_cls=dict( + type='QualityFocalLoss', + use_sigmoid=True, + beta=2.0, + loss_weight=1.0), + loss_dfl=dict(type='DistributionFocalLoss', loss_weight=0.25), + reg_max=16, + loss_bbox=dict(type='GIoULoss', loss_weight=2.0)), + # training and testing settings + train_cfg=dict( + assigner=dict(type='ATSSAssigner', topk=9), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py b/configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py new file mode 100644 index 0000000..b8be601 --- /dev/null +++ b/configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py @@ -0,0 +1,22 @@ +_base_ = './gfl_r50_fpn_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) +# multi-scale training +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=[(1333, 480), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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']), +] +data = dict(train=dict(pipeline=train_pipeline)) diff --git a/configs/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py b/configs/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py new file mode 100644 index 0000000..2539807 --- /dev/null +++ b/configs/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py @@ -0,0 +1,18 @@ +_base_ = './gfl_r50_fpn_mstrain_2x_coco.py' +model = dict( + type='GFL', + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, False, True, True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py b/configs/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py new file mode 100644 index 0000000..effda19 --- /dev/null +++ b/configs/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py @@ -0,0 +1,16 @@ +_base_ = './gfl_r50_fpn_mstrain_2x_coco.py' +model = dict( + type='GFL', + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/gfl/metafile.yml b/configs/gfl/metafile.yml new file mode 100644 index 0000000..8f049c6 --- /dev/null +++ b/configs/gfl/metafile.yml @@ -0,0 +1,134 @@ +Collections: + - Name: Generalized Focal Loss + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Generalized Focal Loss + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/2006.04388 + Title: 'Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection' + README: configs/gfl/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.2.0/mmdet/models/detectors/gfl.py#L6 + Version: v2.2.0 + +Models: + - Name: gfl_r50_fpn_1x_coco + In Collection: Generalized Focal Loss + Config: configs/gfl/gfl_r50_fpn_1x_coco.py + Metadata: + inference time (ms/im): + - value: 51.28 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_1x_coco/gfl_r50_fpn_1x_coco_20200629_121244-25944287.pth + + - Name: gfl_r50_fpn_mstrain_2x_coco + In Collection: Generalized Focal Loss + Config: configs/gfl/gfl_r50_fpn_mstrain_2x_coco.py + Metadata: + inference time (ms/im): + - value: 51.28 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_mstrain_2x_coco/gfl_r50_fpn_mstrain_2x_coco_20200629_213802-37bb1edc.pth + + - Name: gfl_r101_fpn_mstrain_2x_coco + In Collection: Generalized Focal Loss + Config: configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py + Metadata: + inference time (ms/im): + - value: 68.03 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth + + - Name: gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco + In Collection: Generalized Focal Loss + Config: configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py + Metadata: + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco_20200630_102002-134b07df.pth + + - Name: gfl_x101_32x4d_fpn_mstrain_2x_coco + In Collection: Generalized Focal Loss + Config: configs/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco.py + Metadata: + inference time (ms/im): + - value: 82.64 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_x101_32x4d_fpn_mstrain_2x_coco/gfl_x101_32x4d_fpn_mstrain_2x_coco_20200630_102002-50c1ffdb.pth + + - Name: gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco + In Collection: Generalized Focal Loss + Config: configs/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco.py + Metadata: + inference time (ms/im): + - value: 93.46 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 48.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco/gfl_x101_32x4d_fpn_dconv_c4-c5_mstrain_2x_coco_20200630_102002-14a2bf25.pth diff --git a/configs/ghm/README.md b/configs/ghm/README.md new file mode 100644 index 0000000..2a51ed8 --- /dev/null +++ b/configs/ghm/README.md @@ -0,0 +1,23 @@ +# Gradient Harmonized Single-stage Detector + +## Introduction + + + +``` +@inproceedings{li2019gradient, + title={Gradient Harmonized Single-stage Detector}, + author={Li, Buyu and Liu, Yu and Wang, Xiaogang}, + booktitle={AAAI Conference on Artificial Intelligence}, + year={2019} +} +``` + +## Results and Models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| R-50-FPN | pytorch | 1x | 4.0 | 3.3 | 37.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_r50_fpn_1x_coco/retinanet_ghm_r50_fpn_1x_coco_20200130-a437fda3.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_r50_fpn_1x_coco/retinanet_ghm_r50_fpn_1x_coco_20200130_004213.log.json) | +| R-101-FPN | pytorch | 1x | 6.0 | 4.4 | 39.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_r101_fpn_1x_coco/retinanet_ghm_r101_fpn_1x_coco_20200130-c148ee8f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_r101_fpn_1x_coco/retinanet_ghm_r101_fpn_1x_coco_20200130_145259.log.json) | +| X-101-32x4d-FPN | pytorch | 1x | 7.2 | 5.1 | 40.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco/retinanet_ghm_x101_32x4d_fpn_1x_coco_20200131-e4333bd0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco/retinanet_ghm_x101_32x4d_fpn_1x_coco_20200131_113653.log.json) | +| X-101-64x4d-FPN | pytorch | 1x | 10.3 | 5.2 | 41.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco/retinanet_ghm_x101_64x4d_fpn_1x_coco_20200131-dd381cef.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco/retinanet_ghm_x101_64x4d_fpn_1x_coco_20200131_113723.log.json) | diff --git a/configs/ghm/metafile.yml b/configs/ghm/metafile.yml new file mode 100644 index 0000000..b4f488c --- /dev/null +++ b/configs/ghm/metafile.yml @@ -0,0 +1,101 @@ +Collections: + - Name: GHM + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - GHM-C + - GHM-R + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/1811.05181 + Title: 'Gradient Harmonized Single-stage Detector' + README: configs/ghm/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/losses/ghm_loss.py#L21 + Version: v2.0.0 + +Models: + - Name: retinanet_ghm_r50_fpn_1x_coco + In Collection: GHM + Config: configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.0 + inference time (ms/im): + - value: 303.03 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_r50_fpn_1x_coco/retinanet_ghm_r50_fpn_1x_coco_20200130-a437fda3.pth + + - Name: retinanet_ghm_r101_fpn_1x_coco + In Collection: GHM + Config: configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 227.27 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_r101_fpn_1x_coco/retinanet_ghm_r101_fpn_1x_coco_20200130-c148ee8f.pth + + - Name: retinanet_ghm_x101_32x4d_fpn_1x_coco + In Collection: GHM + Config: configs/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.2 + inference time (ms/im): + - value: 196.08 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco/retinanet_ghm_x101_32x4d_fpn_1x_coco_20200131-e4333bd0.pth + + - Name: retinanet_ghm_x101_64x4d_fpn_1x_coco + In Collection: GHM + Config: configs/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 10.3 + inference time (ms/im): + - value: 192.31 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco/retinanet_ghm_x101_64x4d_fpn_1x_coco_20200131-dd381cef.pth diff --git a/configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py b/configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py new file mode 100644 index 0000000..aaf6fc2 --- /dev/null +++ b/configs/ghm/retinanet_ghm_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './retinanet_ghm_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py b/configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py new file mode 100644 index 0000000..61b9751 --- /dev/null +++ b/configs/ghm/retinanet_ghm_r50_fpn_1x_coco.py @@ -0,0 +1,19 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' +model = dict( + bbox_head=dict( + loss_cls=dict( + _delete_=True, + type='GHMC', + bins=30, + momentum=0.75, + use_sigmoid=True, + loss_weight=1.0), + loss_bbox=dict( + _delete_=True, + type='GHMR', + mu=0.02, + bins=10, + momentum=0.7, + loss_weight=10.0))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco.py b/configs/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..cd2e4cc --- /dev/null +++ b/configs/ghm/retinanet_ghm_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './retinanet_ghm_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco.py b/configs/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..b6107d8 --- /dev/null +++ b/configs/ghm/retinanet_ghm_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './retinanet_ghm_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/gn+ws/README.md b/configs/gn+ws/README.md new file mode 100644 index 0000000..8001b0d --- /dev/null +++ b/configs/gn+ws/README.md @@ -0,0 +1,44 @@ +# Weight Standardization + +## Introduction + + + +``` +@article{weightstandardization, + author = {Siyuan Qiao and Huiyu Wang and Chenxi Liu and Wei Shen and Alan Yuille}, + title = {Weight Standardization}, + journal = {arXiv preprint arXiv:1903.10520}, + year = {2019}, +} +``` + +## Results and Models + +Faster R-CNN + +| Backbone | Style | Normalization | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:---------:|:-------:|:-------------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN | pytorch | GN+WS | 1x | 5.9 | 11.7 | 39.7 | - | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco/faster_rcnn_r50_fpn_gn_ws-all_1x_coco_20200130-613d9fe2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco/faster_rcnn_r50_fpn_gn_ws-all_1x_coco_20200130_210936.log.json) | +| R-101-FPN | pytorch | GN+WS | 1x | 8.9 | 9.0 | 41.7 | - | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco/faster_rcnn_r101_fpn_gn_ws-all_1x_coco_20200205-a93b0d75.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco/faster_rcnn_r101_fpn_gn_ws-all_1x_coco_20200205_232146.log.json) | +| X-50-32x4d-FPN | pytorch | GN+WS | 1x | 7.0 | 10.3 | 40.7 | - | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco_20200203-839c5d9d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco_20200203_220113.log.json) | +| X-101-32x4d-FPN | pytorch | GN+WS | 1x | 10.8 | 7.6 | 42.1 | - | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco_20200212-27da1bc2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco_20200212_195302.log.json) | + +Mask R-CNN + +| Backbone | Style | Normalization | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:---------:|:-------:|:-------------:|:---------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN | pytorch | GN+WS | 2x | 7.3 | 10.5 | 40.6 | 36.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco/mask_rcnn_r50_fpn_gn_ws-all_2x_coco_20200226-16acb762.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco/mask_rcnn_r50_fpn_gn_ws-all_2x_coco_20200226_062128.log.json) | +| R-101-FPN | pytorch | GN+WS | 2x | 10.3 | 8.6 | 42.0 | 37.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco/mask_rcnn_r101_fpn_gn_ws-all_2x_coco_20200212-ea357cd9.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco/mask_rcnn_r101_fpn_gn_ws-all_2x_coco_20200212_213627.log.json) | +| X-50-32x4d-FPN | pytorch | GN+WS | 2x | 8.4 | 9.3 | 41.1 | 37.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco_20200216-649fdb6f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco_20200216_201500.log.json) | +| X-101-32x4d-FPN | pytorch | GN+WS | 2x | 12.2 | 7.1 | 42.1 | 37.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco_20200319-33fb95b5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco_20200319_104101.log.json) | +| R-50-FPN | pytorch | GN+WS | 20-23-24e | 7.3 | - | 41.1 | 37.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco_20200213-487d1283.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco_20200213_035123.log.json) | +| R-101-FPN | pytorch | GN+WS | 20-23-24e | 10.3 | - | 43.1 | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco_20200213-57b5a50f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco_20200213_130142.log.json) | +| X-50-32x4d-FPN | pytorch | GN+WS | 20-23-24e | 8.4 | - | 42.1 | 38.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco_20200226-969bcb2c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco_20200226_093732.log.json) | +| X-101-32x4d-FPN | pytorch | GN+WS | 20-23-24e | 12.2 | - | 42.7 | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco_20200316-e6cd35ef.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco_20200316_013741.log.json) | + +Note: + +- GN+WS requires about 5% more memory than GN, and it is only 5% slower than GN. +- In the paper, a 20-23-24e lr schedule is used instead of 2x. +- The X-50-GN and X-101-GN pretrained models are also shared by the authors. diff --git a/configs/gn+ws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py b/configs/gn+ws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py new file mode 100644 index 0000000..cd2cb2b --- /dev/null +++ b/configs/gn+ws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://jhu/resnet101_gn_ws'))) diff --git a/configs/gn+ws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py b/configs/gn+ws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py new file mode 100644 index 0000000..1b326b8 --- /dev/null +++ b/configs/gn+ws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +conv_cfg = dict(type='ConvWS') +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://jhu/resnet50_gn_ws')), + neck=dict(conv_cfg=conv_cfg, norm_cfg=norm_cfg), + roi_head=dict( + bbox_head=dict( + type='Shared4Conv1FCBBoxHead', + conv_out_channels=256, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg))) diff --git a/configs/gn+ws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py b/configs/gn+ws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py new file mode 100644 index 0000000..f64ae89 --- /dev/null +++ b/configs/gn+ws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py @@ -0,0 +1,18 @@ +_base_ = './faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py' +conv_cfg = dict(type='ConvWS') +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://jhu/resnext101_32x4d_gn_ws'))) diff --git a/configs/gn+ws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py b/configs/gn+ws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py new file mode 100644 index 0000000..246851b --- /dev/null +++ b/configs/gn+ws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py @@ -0,0 +1,18 @@ +_base_ = './faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py' +conv_cfg = dict(type='ConvWS') +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + type='ResNeXt', + depth=50, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://jhu/resnext50_32x4d_gn_ws'))) diff --git a/configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py b/configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py new file mode 100644 index 0000000..a790d93 --- /dev/null +++ b/configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py' +# learning policy +lr_config = dict(step=[20, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py b/configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py new file mode 100644 index 0000000..a9fa6a2 --- /dev/null +++ b/configs/gn+ws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py @@ -0,0 +1,6 @@ +_base_ = './mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://jhu/resnet101_gn_ws'))) diff --git a/configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py b/configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py new file mode 100644 index 0000000..5516808 --- /dev/null +++ b/configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py' +# learning policy +lr_config = dict(step=[20, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py b/configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py new file mode 100644 index 0000000..63be60f --- /dev/null +++ b/configs/gn+ws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py @@ -0,0 +1,20 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +conv_cfg = dict(type='ConvWS') +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://jhu/resnet50_gn_ws')), + neck=dict(conv_cfg=conv_cfg, norm_cfg=norm_cfg), + roi_head=dict( + bbox_head=dict( + type='Shared4Conv1FCBBoxHead', + conv_out_channels=256, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg), + mask_head=dict(conv_cfg=conv_cfg, norm_cfg=norm_cfg))) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py b/configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py new file mode 100644 index 0000000..cfa14c9 --- /dev/null +++ b/configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py' +# learning policy +lr_config = dict(step=[20, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py b/configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py new file mode 100644 index 0000000..6498b03 --- /dev/null +++ b/configs/gn+ws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py @@ -0,0 +1,19 @@ +_base_ = './mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py' +# model settings +conv_cfg = dict(type='ConvWS') +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://jhu/resnext101_32x4d_gn_ws'))) diff --git a/configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py b/configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py new file mode 100644 index 0000000..79ce0ad --- /dev/null +++ b/configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py' +# learning policy +lr_config = dict(step=[20, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py b/configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py new file mode 100644 index 0000000..7fac317 --- /dev/null +++ b/configs/gn+ws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py @@ -0,0 +1,19 @@ +_base_ = './mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py' +# model settings +conv_cfg = dict(type='ConvWS') +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + type='ResNeXt', + depth=50, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://jhu/resnext50_32x4d_gn_ws'))) diff --git a/configs/gn+ws/metafile.yml b/configs/gn+ws/metafile.yml new file mode 100644 index 0000000..bc89359 --- /dev/null +++ b/configs/gn+ws/metafile.yml @@ -0,0 +1,263 @@ +Collections: + - Name: Weight Standardization + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Group Normalization + - Weight Standardization + Paper: + URL: https://arxiv.org/abs/1903.10520 + Title: 'Weight Standardization' + README: configs/gn+ws/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/configs/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py + Version: v2.0.0 + +Models: + - Name: faster_rcnn_r50_fpn_gn_ws-all_1x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco.py + Metadata: + Training Memory (GB): 5.9 + inference time (ms/im): + - value: 85.47 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_r50_fpn_gn_ws-all_1x_coco/faster_rcnn_r50_fpn_gn_ws-all_1x_coco_20200130-613d9fe2.pth + + - Name: faster_rcnn_r101_fpn_gn_ws-all_1x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco.py + Metadata: + Training Memory (GB): 8.9 + inference time (ms/im): + - value: 111.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_r101_fpn_gn_ws-all_1x_coco/faster_rcnn_r101_fpn_gn_ws-all_1x_coco_20200205-a93b0d75.pth + + - Name: faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco.py + Metadata: + Training Memory (GB): 7.0 + inference time (ms/im): + - value: 97.09 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco/faster_rcnn_x50_32x4d_fpn_gn_ws-all_1x_coco_20200203-839c5d9d.pth + + - Name: faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco.py + Metadata: + Training Memory (GB): 10.8 + inference time (ms/im): + - value: 131.58 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco/faster_rcnn_x101_32x4d_fpn_gn_ws-all_1x_coco_20200212-27da1bc2.pth + + - Name: mask_rcnn_r50_fpn_gn_ws-all_2x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco.py + Metadata: + Training Memory (GB): 7.3 + inference time (ms/im): + - value: 95.24 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_2x_coco/mask_rcnn_r50_fpn_gn_ws-all_2x_coco_20200226-16acb762.pth + + - Name: mask_rcnn_r101_fpn_gn_ws-all_2x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco.py + Metadata: + Training Memory (GB): 10.3 + inference time (ms/im): + - value: 116.28 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_2x_coco/mask_rcnn_r101_fpn_gn_ws-all_2x_coco_20200212-ea357cd9.pth + + - Name: mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco.py + Metadata: + Training Memory (GB): 8.4 + inference time (ms/im): + - value: 107.53 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco/mask_rcnn_x50_32x4d_fpn_gn_ws-all_2x_coco_20200216-649fdb6f.pth + + - Name: mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco.py + Metadata: + Training Memory (GB): 12.2 + inference time (ms/im): + - value: 140.85 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco/mask_rcnn_x101_32x4d_fpn_gn_ws-all_2x_coco_20200319-33fb95b5.pth + + - Name: mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco.py + Metadata: + Training Memory (GB): 7.3 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_r50_fpn_gn_ws-all_20_23_24e_coco_20200213-487d1283.pth + + - Name: mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco.py + Metadata: + Training Memory (GB): 10.3 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_r101_fpn_gn_ws-all_20_23_24e_coco_20200213-57b5a50f.pth + + - Name: mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco.py + Metadata: + Training Memory (GB): 8.4 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_x50_32x4d_fpn_gn_ws-all_20_23_24e_coco_20200226-969bcb2c.pth + + - Name: mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco + In Collection: Weight Standardization + Config: configs/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco.py + Metadata: + Training Memory (GB): 12.2 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn%2Bws/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco/mask_rcnn_x101_32x4d_fpn_gn_ws-all_20_23_24e_coco_20200316-e6cd35ef.pth diff --git a/configs/gn/README.md b/configs/gn/README.md new file mode 100644 index 0000000..5c6e41f --- /dev/null +++ b/configs/gn/README.md @@ -0,0 +1,31 @@ +# Group Normalization + +## Introduction + + + +```latex +@inproceedings{wu2018group, + title={Group Normalization}, + author={Wu, Yuxin and He, Kaiming}, + booktitle={Proceedings of the European Conference on Computer Vision (ECCV)}, + year={2018} +} +``` + +## Results and Models + +| Backbone | model | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:-------------:|:----------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN (d) | Mask R-CNN | 2x | 7.1 | 11.0 | 40.2 | 36.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_2x_coco/mask_rcnn_r50_fpn_gn-all_2x_coco_20200206-8eee02a6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_2x_coco/mask_rcnn_r50_fpn_gn-all_2x_coco_20200206_050355.log.json) | +| R-50-FPN (d) | Mask R-CNN | 3x | 7.1 | - | 40.5 | 36.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_3x_coco/mask_rcnn_r50_fpn_gn-all_3x_coco_20200214-8b23b1e5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_3x_coco/mask_rcnn_r50_fpn_gn-all_3x_coco_20200214_063512.log.json) | +| R-101-FPN (d) | Mask R-CNN | 2x | 9.9 | 9.0 | 41.9 | 37.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r101_fpn_gn-all_2x_coco/mask_rcnn_r101_fpn_gn-all_2x_coco_20200205-d96b1b50.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r101_fpn_gn-all_2x_coco/mask_rcnn_r101_fpn_gn-all_2x_coco_20200205_234402.log.json) | +| R-101-FPN (d) | Mask R-CNN | 3x | 9.9 | | 42.1 | 38.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r101_fpn_gn-all_3x_coco/mask_rcnn_r101_fpn_gn-all_3x_coco_20200513_181609-0df864f4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r101_fpn_gn-all_3x_coco/mask_rcnn_r101_fpn_gn-all_3x_coco_20200513_181609.log.json) | +| R-50-FPN (c) | Mask R-CNN | 2x | 7.1 | 10.9 | 40.0 | 36.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco_20200207-20d3e849.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco_20200207_225832.log.json) | +| R-50-FPN (c) | Mask R-CNN | 3x | 7.1 | - | 40.1 | 36.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco_20200225-542aefbc.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco_20200225_235135.log.json) | + +**Notes:** + +- (d) means pretrained model converted from Detectron, and (c) means the contributed model pretrained by [@thangvubk](https://github.com/thangvubk). +- The `3x` schedule is epoch [28, 34, 36]. +- **Memory, Train/Inf time is outdated.** diff --git a/configs/gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py b/configs/gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py new file mode 100644 index 0000000..a505ba0 --- /dev/null +++ b/configs/gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py @@ -0,0 +1,7 @@ +_base_ = './mask_rcnn_r50_fpn_gn-all_2x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron/resnet101_gn'))) diff --git a/configs/gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py b/configs/gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py new file mode 100644 index 0000000..12a9d17 --- /dev/null +++ b/configs/gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py @@ -0,0 +1,5 @@ +_base_ = './mask_rcnn_r101_fpn_gn-all_2x_coco.py' + +# learning policy +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py b/configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py new file mode 100644 index 0000000..1de7d98 --- /dev/null +++ b/configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py @@ -0,0 +1,49 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron/resnet50_gn')), + neck=dict(norm_cfg=norm_cfg), + roi_head=dict( + bbox_head=dict( + type='Shared4Conv1FCBBoxHead', + conv_out_channels=256, + norm_cfg=norm_cfg), + mask_head=dict(norm_cfg=norm_cfg))) +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py b/configs/gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py new file mode 100644 index 0000000..f917719 --- /dev/null +++ b/configs/gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py @@ -0,0 +1,5 @@ +_base_ = './mask_rcnn_r50_fpn_gn-all_2x_coco.py' + +# learning policy +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py b/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py new file mode 100644 index 0000000..2f430fd --- /dev/null +++ b/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py @@ -0,0 +1,17 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +norm_cfg = dict(type='GN', num_groups=32, requires_grad=True) +model = dict( + backbone=dict( + norm_cfg=norm_cfg, + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://contrib/resnet50_gn')), + neck=dict(norm_cfg=norm_cfg), + roi_head=dict( + bbox_head=dict( + type='Shared4Conv1FCBBoxHead', + conv_out_channels=256, + norm_cfg=norm_cfg), + mask_head=dict(norm_cfg=norm_cfg))) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py b/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py new file mode 100644 index 0000000..66834f0 --- /dev/null +++ b/configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py @@ -0,0 +1,5 @@ +_base_ = './mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py' + +# learning policy +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/gn/metafile.yml b/configs/gn/metafile.yml new file mode 100644 index 0000000..4a1ecae --- /dev/null +++ b/configs/gn/metafile.yml @@ -0,0 +1,162 @@ +Collections: + - Name: Group Normalization + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Group Normalization + Paper: + URL: https://arxiv.org/abs/1803.08494 + Title: 'Group Normalization' + README: configs/gn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py + Version: v2.0.0 + +Models: + - Name: mask_rcnn_r50_fpn_gn-all_2x_coco + In Collection: Group Normalization + Config: configs/gn/mask_rcnn_r50_fpn_gn-all_2x_coco.py + Metadata: + Training Memory (GB): 7.1 + inference time (ms/im): + - value: 90.91 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_2x_coco/mask_rcnn_r50_fpn_gn-all_2x_coco_20200206-8eee02a6.pth + + - Name: mask_rcnn_r50_fpn_gn-all_3x_coco + In Collection: Group Normalization + Config: configs/gn/mask_rcnn_r50_fpn_gn-all_3x_coco.py + Metadata: + Training Memory (GB): 7.1 + inference time (ms/im): + - value: 90.91 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_3x_coco/mask_rcnn_r50_fpn_gn-all_3x_coco_20200214-8b23b1e5.pth + + - Name: mask_rcnn_r101_fpn_gn-all_2x_coco + In Collection: Group Normalization + Config: configs/gn/mask_rcnn_r101_fpn_gn-all_2x_coco.py + Metadata: + Training Memory (GB): 9.9 + inference time (ms/im): + - value: 111.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r101_fpn_gn-all_2x_coco/mask_rcnn_r101_fpn_gn-all_2x_coco_20200205-d96b1b50.pth + + - Name: mask_rcnn_r101_fpn_gn-all_3x_coco + In Collection: Group Normalization + Config: configs/gn/mask_rcnn_r101_fpn_gn-all_3x_coco.py + Metadata: + Training Memory (GB): 9.9 + inference time (ms/im): + - value: 111.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r101_fpn_gn-all_3x_coco/mask_rcnn_r101_fpn_gn-all_3x_coco_20200513_181609-0df864f4.pth + + - Name: mask_rcnn_r50_fpn_gn-all_contrib_2x_coco + In Collection: Group Normalization + Config: configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco.py + Metadata: + Training Memory (GB): 7.1 + inference time (ms/im): + - value: 91.74 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco/mask_rcnn_r50_fpn_gn-all_contrib_2x_coco_20200207-20d3e849.pth + + - Name: mask_rcnn_r50_fpn_gn-all_contrib_3x_coco + In Collection: Group Normalization + Config: configs/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco.py + Metadata: + Training Memory (GB): 7.1 + inference time (ms/im): + - value: 91.74 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/gn/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco/mask_rcnn_r50_fpn_gn-all_contrib_3x_coco_20200225-542aefbc.pth diff --git a/configs/grid_rcnn/README.md b/configs/grid_rcnn/README.md new file mode 100644 index 0000000..30cb6e0 --- /dev/null +++ b/configs/grid_rcnn/README.md @@ -0,0 +1,35 @@ +# Grid R-CNN + +## Introduction + + + +```latex +@inproceedings{lu2019grid, + title={Grid r-cnn}, + author={Lu, Xin and Li, Buyu and Yue, Yuxin and Li, Quanquan and Yan, Junjie}, + booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition}, + year={2019} +} + +@article{lu2019grid, + title={Grid R-CNN Plus: Faster and Better}, + author={Lu, Xin and Li, Buyu and Yue, Yuxin and Li, Quanquan and Yan, Junjie}, + journal={arXiv preprint arXiv:1906.05688}, + year={2019} +} +``` + +## Results and Models + +| Backbone | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:-----------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50 | 2x | 5.1 | 15.0 | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco/grid_rcnn_r50_fpn_gn-head_2x_coco_20200130-6cca8223.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco/grid_rcnn_r50_fpn_gn-head_2x_coco_20200130_221140.log.json) | +| R-101 | 2x | 7.0 | 12.6 | 41.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco/grid_rcnn_r101_fpn_gn-head_2x_coco_20200309-d6eca030.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco/grid_rcnn_r101_fpn_gn-head_2x_coco_20200309_164224.log.json) | +| X-101-32x4d | 2x | 8.3 | 10.8 | 42.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco_20200130-d8f0e3ff.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco_20200130_215413.log.json) | +| X-101-64x4d | 2x | 11.3 | 7.7 | 43.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco_20200204-ec76a754.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco_20200204_080641.log.json) | + +**Notes:** + +- All models are trained with 8 GPUs instead of 32 GPUs in the original paper. +- The warming up lasts for 1 epoch and `2x` here indicates 25 epochs. diff --git a/configs/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco.py b/configs/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco.py new file mode 100644 index 0000000..1bb5889 --- /dev/null +++ b/configs/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco.py @@ -0,0 +1,7 @@ +_base_ = './grid_rcnn_r50_fpn_gn-head_2x_coco.py' + +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_1x_coco.py b/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_1x_coco.py new file mode 100644 index 0000000..4aa00ec --- /dev/null +++ b/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = ['grid_rcnn_r50_fpn_gn-head_2x_coco.py'] +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[8, 11]) +checkpoint_config = dict(interval=1) +# runtime settings +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco.py b/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco.py new file mode 100644 index 0000000..df63cd5 --- /dev/null +++ b/configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco.py @@ -0,0 +1,131 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', '../_base_/default_runtime.py' +] +# model settings +model = dict( + type='GridRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + type='GridRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=dict( + type='Shared2FCBBoxHead', + with_reg=False, + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False), + grid_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + grid_head=dict( + type='GridHead', + grid_points=9, + num_convs=8, + in_channels=256, + point_feat_channels=64, + norm_cfg=dict(type='GN', num_groups=36), + loss_grid=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=15))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_radius=1, + pos_weight=-1, + max_num_grid=192, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.03, + nms=dict(type='nms', iou_threshold=0.3), + max_per_img=100))) +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=3665, + warmup_ratio=1.0 / 80, + step=[17, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=25) diff --git a/configs/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py b/configs/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py new file mode 100644 index 0000000..3bc8516 --- /dev/null +++ b/configs/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py @@ -0,0 +1,24 @@ +_base_ = './grid_rcnn_r50_fpn_gn-head_2x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) +# optimizer +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=3665, + warmup_ratio=1.0 / 80, + step=[17, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=25) diff --git a/configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py b/configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py new file mode 100644 index 0000000..c78f8f6 --- /dev/null +++ b/configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py @@ -0,0 +1,13 @@ +_base_ = './grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/grid_rcnn/metafile.yml b/configs/grid_rcnn/metafile.yml new file mode 100644 index 0000000..d1aa851 --- /dev/null +++ b/configs/grid_rcnn/metafile.yml @@ -0,0 +1,101 @@ +Collections: + - Name: Grid R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - RPN + - Dilated Convolution + - ResNet + - RoIAlign + Paper: + URL: https://arxiv.org/abs/1906.05688 + Title: 'Grid R-CNN' + README: configs/grid_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/grid_rcnn.py#L6 + Version: v2.0.0 + +Models: + - Name: grid_rcnn_r50_fpn_gn-head_2x_coco + In Collection: Grid R-CNN + Config: configs/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco.py + Metadata: + Training Memory (GB): 5.1 + inference time (ms/im): + - value: 66.67 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_r50_fpn_gn-head_2x_coco/grid_rcnn_r50_fpn_gn-head_2x_coco_20200130-6cca8223.pth + + - Name: grid_rcnn_r101_fpn_gn-head_2x_coco + In Collection: Grid R-CNN + Config: configs/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco.py + Metadata: + Training Memory (GB): 7.0 + inference time (ms/im): + - value: 79.37 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_r101_fpn_gn-head_2x_coco/grid_rcnn_r101_fpn_gn-head_2x_coco_20200309-d6eca030.pth + + - Name: grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco + In Collection: Grid R-CNN + Config: configs/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco.py + Metadata: + Training Memory (GB): 8.3 + inference time (ms/im): + - value: 92.59 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco/grid_rcnn_x101_32x4d_fpn_gn-head_2x_coco_20200130-d8f0e3ff.pth + + - Name: grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco + In Collection: Grid R-CNN + Config: configs/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco.py + Metadata: + Training Memory (GB): 11.3 + inference time (ms/im): + - value: 129.87 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/grid_rcnn/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco/grid_rcnn_x101_64x4d_fpn_gn-head_2x_coco_20200204-ec76a754.pth diff --git a/configs/groie/README.md b/configs/groie/README.md new file mode 100644 index 0000000..42d4b9f --- /dev/null +++ b/configs/groie/README.md @@ -0,0 +1,62 @@ +# GRoIE + +## A novel Region of Interest Extraction Layer for Instance Segmentation + +By Leonardo Rossi, Akbar Karimi and Andrea Prati from +[IMPLab](http://implab.ce.unipr.it/). + +We provide configs to reproduce the results in the paper for +"*A novel Region of Interest Extraction Layer for Instance Segmentation*" +on COCO object detection. + +## Introduction + + + +This paper is motivated by the need to overcome to the limitations of existing +RoI extractors which select only one (the best) layer from FPN. + +Our intuition is that all the layers of FPN retain useful information. + +Therefore, the proposed layer (called Generic RoI Extractor - **GRoIE**) +introduces non-local building blocks and attention mechanisms to boost the +performance. + +## Results and models + +The results on COCO 2017 minival (5k images) are shown in the below table. + +### Application of GRoIE to different architectures + +| Backbone | Method | Lr schd | box AP | mask AP | Config | Download| +| :-------: | :--------------: | :-----: | :----: | :-----: | :-------:| :--------:| +| R-50-FPN | Faster Original | 1x | 37.4 | | [config](../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130_204655.log.json) | +| R-50-FPN | + GRoIE | 1x | 38.3 | | [config](./faster_rcnn_r50_fpn_groie_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/groie/faster_rcnn_r50_fpn_groie_1x_coco/faster_rcnn_r50_fpn_groie_1x_coco_20200604_211715-66ee9516.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/groie/faster_rcnn_r50_fpn_groie_1x_coco/faster_rcnn_r50_fpn_groie_1x_coco_20200604_211715.log.json) | +| R-50-FPN | Grid R-CNN | 1x | 39.1 | | [config](./grid_rcnn_r50_fpn_gn-head_1x_coco.py)| [model](https://download.openmmlab.com/mmdetection/v2.0/groie/grid_rcnn_r50_fpn_gn-head_1x_coco/grid_rcnn_r50_fpn_gn-head_1x_coco_20200605_202059-64f00ee8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/groie/grid_rcnn_r50_fpn_gn-head_1x_coco/grid_rcnn_r50_fpn_gn-head_1x_coco_20200605_202059.log.json) | +| R-50-FPN | + GRoIE | 1x | | | [config](./grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py)|| +| R-50-FPN | Mask R-CNN | 1x | 38.2 | 34.7 | [config](../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py)| [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205_050542.log.json) | +| R-50-FPN | + GRoIE | 1x | 39.0 | 36.0 | [config](./mask_rcnn_r50_fpn_groie_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r50_fpn_groie_1x_coco/mask_rcnn_r50_fpn_groie_1x_coco_20200604_211715-50d90c74.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r50_fpn_groie_1x_coco/mask_rcnn_r50_fpn_groie_1x_coco_20200604_211715.log.json) | +| R-50-FPN | GC-Net | 1x | 40.7 | 36.5 | [config](../gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200202-50b90e5c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200202_085547.log.json) | +| R-50-FPN | + GRoIE | 1x | 41.0 | 37.8 | [config](./mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py) |[model](https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco_20200604_211715-42eb79e1.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco_20200604_211715-42eb79e1.pth) | +| R-101-FPN | GC-Net | 1x | 42.2 | 37.8 | [config](../gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200206-8407a3f0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco_20200206_142508.log.json) | +| R-101-FPN | + GRoIE | 1x | 42.6 | 38.7 | [config](./mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py)| [model](https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco_20200607_224507-8daae01c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco_20200607_224507.log.json) | + +## Citation + +If you use this work or benchmark in your research, please cite this project. + +```latex +@inproceedings{rossi2021novel, + title={A novel region of interest extraction layer for instance segmentation}, + author={Rossi, Leonardo and Karimi, Akbar and Prati, Andrea}, + booktitle={2020 25th International Conference on Pattern Recognition (ICPR)}, + pages={2203--2209}, + year={2021}, + organization={IEEE} +} +``` + +## Contact + +The implementation of GRoIE is currently maintained by +[Leonardo Rossi](https://github.com/hachreak/). diff --git a/configs/groie/faster_rcnn_r50_fpn_groie_1x_coco.py b/configs/groie/faster_rcnn_r50_fpn_groie_1x_coco.py new file mode 100644 index 0000000..0fc528b --- /dev/null +++ b/configs/groie/faster_rcnn_r50_fpn_groie_1x_coco.py @@ -0,0 +1,25 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +# model settings +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='GenericRoIExtractor', + aggregation='sum', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)))) diff --git a/configs/groie/grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py b/configs/groie/grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py new file mode 100644 index 0000000..8e4b4ab --- /dev/null +++ b/configs/groie/grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py @@ -0,0 +1,45 @@ +_base_ = '../grid_rcnn/grid_rcnn_r50_fpn_gn-head_1x_coco.py' +# model settings +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='GenericRoIExtractor', + aggregation='sum', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)), + grid_roi_extractor=dict( + type='GenericRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)))) diff --git a/configs/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py b/configs/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py new file mode 100644 index 0000000..8b83722 --- /dev/null +++ b/configs/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py @@ -0,0 +1,45 @@ +_base_ = '../gcnet/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py' +# model settings +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='GenericRoIExtractor', + aggregation='sum', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)), + mask_roi_extractor=dict( + type='GenericRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)))) diff --git a/configs/groie/mask_rcnn_r50_fpn_groie_1x_coco.py b/configs/groie/mask_rcnn_r50_fpn_groie_1x_coco.py new file mode 100644 index 0000000..81dfb48 --- /dev/null +++ b/configs/groie/mask_rcnn_r50_fpn_groie_1x_coco.py @@ -0,0 +1,45 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +# model settings +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='GenericRoIExtractor', + aggregation='sum', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)), + mask_roi_extractor=dict( + type='GenericRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)))) diff --git a/configs/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py b/configs/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py new file mode 100644 index 0000000..852c5ca --- /dev/null +++ b/configs/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py @@ -0,0 +1,45 @@ +_base_ = '../gcnet/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_1x_coco.py' +# model settings +model = dict( + roi_head=dict( + bbox_roi_extractor=dict( + type='GenericRoIExtractor', + aggregation='sum', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)), + mask_roi_extractor=dict( + type='GenericRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32], + pre_cfg=dict( + type='ConvModule', + in_channels=256, + out_channels=256, + kernel_size=5, + padding=2, + inplace=False, + ), + post_cfg=dict( + type='GeneralizedAttention', + in_channels=256, + spatial_range=-1, + num_heads=6, + attention_type='0100', + kv_stride=2)))) diff --git a/configs/groie/metafile.yml b/configs/groie/metafile.yml new file mode 100644 index 0000000..269cb39 --- /dev/null +++ b/configs/groie/metafile.yml @@ -0,0 +1,93 @@ +Collections: + - Name: GRoIE + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Generic RoI Extractor + - FPN + - RPN + - ResNet + - RoIAlign + Paper: + URL: https://arxiv.org/abs/2004.13665 + Title: 'A novel Region of Interest Extraction Layer for Instance Segmentation' + README: configs/groie/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.1.0/mmdet/models/roi_heads/roi_extractors/groie.py#L15 + Version: v2.1.0 + +Models: + - Name: faster_rcnn_r50_fpn_groie_1x_coco + In Collection: GRoIE + Config: configs/groie/faster_rcnn_r50_fpn_groie_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/groie/faster_rcnn_r50_fpn_groie_1x_coco/faster_rcnn_r50_fpn_groie_1x_coco_20200604_211715-66ee9516.pth + + - Name: grid_rcnn_r50_fpn_gn-head_groie_1x_coco + In Collection: GRoIE + Config: configs/groie/grid_rcnn_r50_fpn_gn-head_groie_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.1 + + - Name: mask_rcnn_r50_fpn_groie_1x_coco + In Collection: GRoIE + Config: configs/groie/mask_rcnn_r50_fpn_groie_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r50_fpn_groie_1x_coco/mask_rcnn_r50_fpn_groie_1x_coco_20200604_211715-50d90c74.pth + + - Name: mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco + In Collection: GRoIE + Config: configs/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco/mask_rcnn_r50_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco_20200604_211715-42eb79e1.pth + + - Name: mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco + In Collection: GRoIE + Config: configs/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/groie/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco/mask_rcnn_r101_fpn_syncbn-backbone_r4_gcb_c3-c5_groie_1x_coco_20200607_224507-8daae01c.pth diff --git a/configs/guided_anchoring/README.md b/configs/guided_anchoring/README.md new file mode 100644 index 0000000..34d6b0d --- /dev/null +++ b/configs/guided_anchoring/README.md @@ -0,0 +1,49 @@ +# Region Proposal by Guided Anchoring + +## Introduction + + + +We provide config files to reproduce the results in the CVPR 2019 paper for [Region Proposal by Guided Anchoring](https://arxiv.org/abs/1901.03278). + +```latex +@inproceedings{wang2019region, + title={Region Proposal by Guided Anchoring}, + author={Jiaqi Wang and Kai Chen and Shuo Yang and Chen Change Loy and Dahua Lin}, + booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, + year={2019} +} +``` + +## Results and Models + +The results on COCO 2017 val is shown in the below table. (results on test-dev are usually slightly higher than val). + +| Method | Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | AR 1000 | Config | Download | +| :----: | :-------------: | :-----: | :-----: | :------: | :------------: | :-----: | :------: | :--------: | +| GA-RPN | R-50-FPN | caffe | 1x | 5.3 | 15.8 | 68.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco/ga_rpn_r50_caffe_fpn_1x_coco_20200531-899008a6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco/ga_rpn_r50_caffe_fpn_1x_coco_20200531_011819.log.json) | +| GA-RPN | R-101-FPN | caffe | 1x | 7.3 | 13.0 | 69.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco/ga_rpn_r101_caffe_fpn_1x_coco_20200531-ca9ba8fb.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco/ga_rpn_r101_caffe_fpn_1x_coco_20200531_011812.log.json) | +| GA-RPN | X-101-32x4d-FPN | pytorch | 1x | 8.5 | 10.0 | 70.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco/ga_rpn_x101_32x4d_fpn_1x_coco_20200220-c28d1b18.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco/ga_rpn_x101_32x4d_fpn_1x_coco_20200220_221326.log.json) | +| GA-RPN | X-101-64x4d-FPN | pytorch | 1x | 7.1 | 7.5 | 71.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco/ga_rpn_x101_64x4d_fpn_1x_coco_20200225-3c6e1aa2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco/ga_rpn_x101_64x4d_fpn_1x_coco_20200225_152704.log.json) | + +| Method | Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :------------: | :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| GA-Faster RCNN | R-50-FPN | caffe | 1x | 5.5 | | 39.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco/ga_faster_r50_caffe_fpn_1x_coco_20200702_000718-a11ccfe6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco/ga_faster_r50_caffe_fpn_1x_coco_20200702_000718.log.json) | +| GA-Faster RCNN | R-101-FPN | caffe | 1x | 7.5 | | 41.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco/ga_faster_r101_caffe_fpn_1x_coco_bbox_mAP-0.415_20200505_115528-fb82e499.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco/ga_faster_r101_caffe_fpn_1x_coco_20200505_115528.log.json) | +| GA-Faster RCNN | X-101-32x4d-FPN | pytorch | 1x | 8.7 | 9.7 | 43.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco/ga_faster_x101_32x4d_fpn_1x_coco_20200215-1ded9da3.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco/ga_faster_x101_32x4d_fpn_1x_coco_20200215_184547.log.json) | +| GA-Faster RCNN | X-101-64x4d-FPN | pytorch | 1x | 11.8 | 7.3 | 43.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco/ga_faster_x101_64x4d_fpn_1x_coco_20200215-0fa7bde7.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco/ga_faster_x101_64x4d_fpn_1x_coco_20200215_104455.log.json) | +| GA-RetinaNet | R-50-FPN | caffe | 1x | 3.5 | 16.8 | 36.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco/ga_retinanet_r50_caffe_fpn_1x_coco_20201020-39581c6f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco/ga_retinanet_r50_caffe_fpn_1x_coco_20201020_225450.log.json) | +| GA-RetinaNet | R-101-FPN | caffe | 1x | 5.5 | 12.9 | 39.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco/ga_retinanet_r101_caffe_fpn_1x_coco_20200531-6266453c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco/ga_retinanet_r101_caffe_fpn_1x_coco_20200531_012847.log.json) | +| GA-RetinaNet | X-101-32x4d-FPN | pytorch | 1x | 6.9 | 10.6 | 40.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco/ga_retinanet_x101_32x4d_fpn_1x_coco_20200219-40c56caa.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco/ga_retinanet_x101_32x4d_fpn_1x_coco_20200219_223025.log.json) | +| GA-RetinaNet | X-101-64x4d-FPN | pytorch | 1x | 9.9 | 7.7 | 41.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco/ga_retinanet_x101_64x4d_fpn_1x_coco_20200226-ef9f7f1f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco/ga_retinanet_x101_64x4d_fpn_1x_coco_20200226_221123.log.json) | + +- In the Guided Anchoring paper, `score_thr` is set to 0.001 in Fast/Faster RCNN and 0.05 in RetinaNet for both baselines and Guided Anchoring. + +- Performance on COCO test-dev benchmark are shown as follows. + +| Method | Backbone | Style | Lr schd | Aug Train | Score thr | AP | AP_50 | AP_75 | AP_small | AP_medium | AP_large | Download | +| :------------: | :-------: | :---: | :-----: | :-------: | :-------: | :---: | :---: | :---: | :------: | :-------: | :------: | :------: | +| GA-Faster RCNN | R-101-FPN | caffe | 1x | F | 0.05 | | | | | | | | +| GA-Faster RCNN | R-101-FPN | caffe | 1x | F | 0.001 | | | | | | | | +| GA-RetinaNet | R-101-FPN | caffe | 1x | F | 0.05 | | | | | | | | +| GA-RetinaNet | R-101-FPN | caffe | 2x | T | 0.05 | | | | | | | | diff --git a/configs/guided_anchoring/ga_fast_r50_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_fast_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..8fc203c --- /dev/null +++ b/configs/guided_anchoring/ga_fast_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,65 @@ +_base_ = '../fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + roi_head=dict( + bbox_head=dict(bbox_coder=dict(target_stds=[0.05, 0.05, 0.1, 0.1]))), + # model training and testing settings + train_cfg=dict( + rcnn=dict( + assigner=dict(pos_iou_thr=0.6, neg_iou_thr=0.6, min_pos_iou=0.6), + sampler=dict(num=256))), + test_cfg=dict(rcnn=dict(score_thr=1e-3))) +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=300), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'proposals', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadProposals', num_max_proposals=None), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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', 'proposals']), + ]) +] +data = dict( + train=dict( + proposal_file=data_root + 'proposals/ga_rpn_r50_fpn_1x_train2017.pkl', + pipeline=train_pipeline), + val=dict( + proposal_file=data_root + 'proposals/ga_rpn_r50_fpn_1x_val2017.pkl', + pipeline=test_pipeline), + test=dict( + proposal_file=data_root + 'proposals/ga_rpn_r50_fpn_1x_val2017.pkl', + pipeline=test_pipeline)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..a40e7c6 --- /dev/null +++ b/configs/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './ga_faster_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..b0add92 --- /dev/null +++ b/configs/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,65 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + rpn_head=dict( + _delete_=True, + type='GARPNHead', + in_channels=256, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=8, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[8], + strides=[4, 8, 16, 32, 64]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.14, 0.14]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.11, 0.11]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), + roi_head=dict( + bbox_head=dict(bbox_coder=dict(target_stds=[0.05, 0.05, 0.1, 0.1]))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + center_ratio=0.2, + ignore_ratio=0.5), + rpn_proposal=dict(nms_post=1000, max_per_img=300), + rcnn=dict( + assigner=dict(pos_iou_thr=0.6, neg_iou_thr=0.6, min_pos_iou=0.6), + sampler=dict(type='RandomSampler', num=256))), + test_cfg=dict( + rpn=dict(nms_post=1000, max_per_img=300), rcnn=dict(score_thr=1e-3))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_faster_r50_fpn_1x_coco.py b/configs/guided_anchoring/ga_faster_r50_fpn_1x_coco.py new file mode 100644 index 0000000..e3d8238 --- /dev/null +++ b/configs/guided_anchoring/ga_faster_r50_fpn_1x_coco.py @@ -0,0 +1,65 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + rpn_head=dict( + _delete_=True, + type='GARPNHead', + in_channels=256, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=8, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[8], + strides=[4, 8, 16, 32, 64]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.14, 0.14]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.11, 0.11]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), + roi_head=dict( + bbox_head=dict(bbox_coder=dict(target_stds=[0.05, 0.05, 0.1, 0.1]))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + center_ratio=0.2, + ignore_ratio=0.5), + rpn_proposal=dict(nms_post=1000, max_per_img=300), + rcnn=dict( + assigner=dict(pos_iou_thr=0.6, neg_iou_thr=0.6, min_pos_iou=0.6), + sampler=dict(type='RandomSampler', num=256))), + test_cfg=dict( + rpn=dict(nms_post=1000, max_per_img=300), rcnn=dict(score_thr=1e-3))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco.py b/configs/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..f1dda94 --- /dev/null +++ b/configs/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ga_faster_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco.py b/configs/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..fb9e2af --- /dev/null +++ b/configs/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ga_faster_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..1b1cccd --- /dev/null +++ b/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './ga_retinanet_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_mstrain_2x.py b/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_mstrain_2x.py new file mode 100644 index 0000000..260895b --- /dev/null +++ b/configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_mstrain_2x.py @@ -0,0 +1,169 @@ +_base_ = '../_base_/default_runtime.py' + +# model settings +model = dict( + type='RetinaNet', + backbone=dict( + type='ResNet', + depth=101, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs=True, + num_outs=5), + bbox_head=dict( + type='GARetinaHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=4, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[8, 16, 32, 64, 128]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[4], + strides=[8, 16, 32, 64, 128]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=0.04, loss_weight=1.0))) +# training and testing settings +train_cfg = dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0.4, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + center_ratio=0.2, + ignore_ratio=0.5, + debug=False) +test_cfg = dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100) +# dataset settings +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 480), (1333, 960)], + keep_ratio=True, + multiscale_mode='range'), + 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=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) +evaluation = dict(interval=1, metric='bbox') +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[16, 22]) +checkpoint_config = dict(interval=1) +# yapf:disable +log_config = dict( + interval=50, + hooks=[ + dict(type='TextLoggerHook'), + # dict(type='TensorboardLoggerHook') + ]) +# yapf:enable +# runtime settings +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..3351201 --- /dev/null +++ b/configs/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,62 @@ +_base_ = '../retinanet/retinanet_r50_caffe_fpn_1x_coco.py' +model = dict( + bbox_head=dict( + _delete_=True, + type='GARetinaHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=4, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[8, 16, 32, 64, 128]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[4], + strides=[8, 16, 32, 64, 128]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=0.04, loss_weight=1.0)), + # training and testing settings + train_cfg=dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0.4, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + assigner=dict(neg_iou_thr=0.5, min_pos_iou=0.0), + center_ratio=0.2, + ignore_ratio=0.5)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_retinanet_r50_fpn_1x_coco.py b/configs/guided_anchoring/ga_retinanet_r50_fpn_1x_coco.py new file mode 100644 index 0000000..7694723 --- /dev/null +++ b/configs/guided_anchoring/ga_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,62 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' +model = dict( + bbox_head=dict( + _delete_=True, + type='GARetinaHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=4, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[8, 16, 32, 64, 128]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[4], + strides=[8, 16, 32, 64, 128]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=0.04, loss_weight=1.0)), + # training and testing settings + train_cfg=dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0.4, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + assigner=dict(neg_iou_thr=0.5, min_pos_iou=0.0), + center_ratio=0.2, + ignore_ratio=0.5)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco.py b/configs/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..c5eb34f --- /dev/null +++ b/configs/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ga_retinanet_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco.py b/configs/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..5c69a6f --- /dev/null +++ b/configs/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ga_retinanet_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..039703e --- /dev/null +++ b/configs/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = './ga_rpn_r50_caffe_fpn_1x_coco.py' +# model settings +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco.py b/configs/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..7830894 --- /dev/null +++ b/configs/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,58 @@ +_base_ = '../rpn/rpn_r50_caffe_fpn_1x_coco.py' +model = dict( + rpn_head=dict( + _delete_=True, + type='GARPNHead', + in_channels=256, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=8, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[8], + strides=[4, 8, 16, 32, 64]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.14, 0.14]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.11, 0.11]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), + # model training and testing settings + train_cfg=dict( + rpn=dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + center_ratio=0.2, + ignore_ratio=0.5)), + test_cfg=dict(rpn=dict(nms_post=1000))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_rpn_r50_fpn_1x_coco.py b/configs/guided_anchoring/ga_rpn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..27ab3e7 --- /dev/null +++ b/configs/guided_anchoring/ga_rpn_r50_fpn_1x_coco.py @@ -0,0 +1,58 @@ +_base_ = '../rpn/rpn_r50_fpn_1x_coco.py' +model = dict( + rpn_head=dict( + _delete_=True, + type='GARPNHead', + in_channels=256, + feat_channels=256, + approx_anchor_generator=dict( + type='AnchorGenerator', + octave_base_scale=8, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + square_anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + scales=[8], + strides=[4, 8, 16, 32, 64]), + anchor_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.14, 0.14]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.07, 0.07, 0.11, 0.11]), + loc_filter_thr=0.01, + loss_loc=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), + # model training and testing settings + train_cfg=dict( + rpn=dict( + ga_assigner=dict( + type='ApproxMaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + ga_sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + center_ratio=0.2, + ignore_ratio=0.5)), + test_cfg=dict(rpn=dict(nms_post=1000))) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco.py b/configs/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..cccc985 --- /dev/null +++ b/configs/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ga_rpn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco.py b/configs/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..4e134d2 --- /dev/null +++ b/configs/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ga_rpn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/guided_anchoring/metafile.yml b/configs/guided_anchoring/metafile.yml new file mode 100644 index 0000000..3019d4a --- /dev/null +++ b/configs/guided_anchoring/metafile.yml @@ -0,0 +1,246 @@ +Collections: + - Name: Guided Anchoring + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - Guided Anchoring + - ResNet + Paper: + URL: https://arxiv.org/abs/1901.03278 + Title: 'Region Proposal by Guided Anchoring' + README: configs/guided_anchoring/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/dense_heads/ga_retina_head.py#L10 + Version: v2.0.0 + +Models: + - Name: ga_rpn_r50_caffe_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.3 + inference time (ms/im): + - value: 63.29 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Region Proposal + Dataset: COCO + Metrics: + AR@1000: 68.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_r50_caffe_fpn_1x_coco/ga_rpn_r50_caffe_fpn_1x_coco_20200531-899008a6.pth + + - Name: ga_rpn_r101_caffe_fpn_1x_coco.py + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco.py.py + Metadata: + Training Memory (GB): 7.3 + inference time (ms/im): + - value: 76.92 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Region Proposal + Dataset: COCO + Metrics: + AR@1000: 69.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_r101_caffe_fpn_1x_coco/ga_rpn_r101_caffe_fpn_1x_coco_20200531-ca9ba8fb.pth + + - Name: ga_rpn_x101_32x4d_fpn_1x_coco.py + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco.py.py + Metadata: + Training Memory (GB): 8.5 + inference time (ms/im): + - value: 100 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Region Proposal + Dataset: COCO + Metrics: + AR@1000: 70.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_x101_32x4d_fpn_1x_coco/ga_rpn_x101_32x4d_fpn_1x_coco_20200220-c28d1b18.pth + + - Name: ga_rpn_x101_64x4d_fpn_1x_coco.py.py + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco.py.py.py + Metadata: + Training Memory (GB): 7.1 + inference time (ms/im): + - value: 133.33 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Region Proposal + Dataset: COCO + Metrics: + AR@1000: 70.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_rpn_x101_64x4d_fpn_1x_coco/ga_rpn_x101_64x4d_fpn_1x_coco_20200225-3c6e1aa2.pth + + - Name: ga_faster_r50_caffe_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_r50_caffe_fpn_1x_coco/ga_faster_r50_caffe_fpn_1x_coco_20200702_000718-a11ccfe6.pth + + - Name: ga_faster_r101_caffe_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_r101_caffe_fpn_1x_coco/ga_faster_r101_caffe_fpn_1x_coco_bbox_mAP-0.415_20200505_115528-fb82e499.pth + + - Name: ga_faster_x101_32x4d_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 8.7 + inference time (ms/im): + - value: 103.09 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_x101_32x4d_fpn_1x_coco/ga_faster_x101_32x4d_fpn_1x_coco_20200215-1ded9da3.pth + + - Name: ga_faster_x101_64x4d_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 11.8 + inference time (ms/im): + - value: 136.99 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_faster_x101_64x4d_fpn_1x_coco/ga_faster_x101_64x4d_fpn_1x_coco_20200215-0fa7bde7.pth + + - Name: ga_retinanet_r50_caffe_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.5 + inference time (ms/im): + - value: 59.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_r50_caffe_fpn_1x_coco/ga_retinanet_r50_caffe_fpn_1x_coco_20201020-39581c6f.pth + + - Name: ga_retinanet_r101_caffe_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.5 + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_r101_caffe_fpn_1x_coco/ga_retinanet_r101_caffe_fpn_1x_coco_20200531-6266453c.pth + + - Name: ga_retinanet_x101_32x4d_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.9 + inference time (ms/im): + - value: 94.34 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_x101_32x4d_fpn_1x_coco/ga_retinanet_x101_32x4d_fpn_1x_coco_20200219-40c56caa.pth + + - Name: ga_retinanet_x101_64x4d_fpn_1x_coco + In Collection: Guided Anchoring + Config: configs/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 9.9 + inference time (ms/im): + - value: 129.87 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/guided_anchoring/ga_retinanet_x101_64x4d_fpn_1x_coco/ga_retinanet_x101_64x4d_fpn_1x_coco_20200226-ef9f7f1f.pth diff --git a/configs/hrnet/README.md b/configs/hrnet/README.md new file mode 100644 index 0000000..bff5ce0 --- /dev/null +++ b/configs/hrnet/README.md @@ -0,0 +1,88 @@ +# High-resolution networks (HRNets) for object detection + +## Introduction + + + +```latex +@inproceedings{SunXLW19, + title={Deep High-Resolution Representation Learning for Human Pose Estimation}, + author={Ke Sun and Bin Xiao and Dong Liu and Jingdong Wang}, + booktitle={CVPR}, + year={2019} +} + +@article{SunZJCXLMWLW19, + title={High-Resolution Representations for Labeling Pixels and Regions}, + author={Ke Sun and Yang Zhao and Borui Jiang and Tianheng Cheng and Bin Xiao + and Dong Liu and Yadong Mu and Xinggang Wang and Wenyu Liu and Jingdong Wang}, + journal = {CoRR}, + volume = {abs/1904.04514}, + year={2019} +} +``` + +## Results and Models + +### Faster R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :-------------:|:------:| :------:| :--------:| +| HRNetV2p-W18 | pytorch | 1x | 6.6 | 13.4 | 36.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco/faster_rcnn_hrnetv2p_w18_1x_coco_20200130-56651a6d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco/faster_rcnn_hrnetv2p_w18_1x_coco_20200130_211246.log.json) | +| HRNetV2p-W18 | pytorch | 2x | 6.6 | - | 38.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco/faster_rcnn_hrnetv2p_w18_2x_coco_20200702_085731-a4ec0611.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco/faster_rcnn_hrnetv2p_w18_2x_coco_20200702_085731.log.json) | +| HRNetV2p-W32 | pytorch | 1x | 9.0 | 12.4 | 40.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco/faster_rcnn_hrnetv2p_w32_1x_coco_20200130-6e286425.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco/faster_rcnn_hrnetv2p_w32_1x_coco_20200130_204442.log.json) | +| HRNetV2p-W32 | pytorch | 2x | 9.0 | - | 41.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco/faster_rcnn_hrnetv2p_w32_2x_coco_20200529_015927-976a9c15.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco/faster_rcnn_hrnetv2p_w32_2x_coco_20200529_015927.log.json) | +| HRNetV2p-W40 | pytorch | 1x | 10.4 | 10.5 | 41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco/faster_rcnn_hrnetv2p_w40_1x_coco_20200210-95c1f5ce.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco/faster_rcnn_hrnetv2p_w40_1x_coco_20200210_125315.log.json) | +| HRNetV2p-W40 | pytorch | 2x | 10.4 | - | 42.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco/faster_rcnn_hrnetv2p_w40_2x_coco_20200512_161033-0f236ef4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco/faster_rcnn_hrnetv2p_w40_2x_coco_20200512_161033.log.json) | + +### Mask R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :-------------:|:------:| :------:|:------:|:--------:| +| HRNetV2p-W18 | pytorch | 1x | 7.0 | 11.7 | 37.7 | 34.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco/mask_rcnn_hrnetv2p_w18_1x_coco_20200205-1c3d78ed.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco/mask_rcnn_hrnetv2p_w18_1x_coco_20200205_232523.log.json) | +| HRNetV2p-W18 | pytorch | 2x | 7.0 | - | 39.8 | 36.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco/mask_rcnn_hrnetv2p_w18_2x_coco_20200212-b3c825b1.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco/mask_rcnn_hrnetv2p_w18_2x_coco_20200212_134222.log.json) | +| HRNetV2p-W32 | pytorch | 1x | 9.4 | 11.3 | 41.2 | 37.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco/mask_rcnn_hrnetv2p_w32_1x_coco_20200207-b29f616e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco/mask_rcnn_hrnetv2p_w32_1x_coco_20200207_055017.log.json) | +| HRNetV2p-W32 | pytorch | 2x | 9.4 | - | 42.5 | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco/mask_rcnn_hrnetv2p_w32_2x_coco_20200213-45b75b4d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco/mask_rcnn_hrnetv2p_w32_2x_coco_20200213_150518.log.json) | +| HRNetV2p-W40 | pytorch | 1x | 10.9 | | 42.1 | 37.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco/mask_rcnn_hrnetv2p_w40_1x_coco_20200511_015646-66738b35.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco/mask_rcnn_hrnetv2p_w40_1x_coco_20200511_015646.log.json) | +| HRNetV2p-W40 | pytorch | 2x | 10.9 | | 42.8 | 38.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco/mask_rcnn_hrnetv2p_w40_2x_coco_20200512_163732-aed5e4ab.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco/mask_rcnn_hrnetv2p_w40_2x_coco_20200512_163732.log.json) | + +### Cascade R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :-------------:|:------:| :------: | :--------: | +| HRNetV2p-W18 | pytorch | 20e | 7.0 | 11.0 | 41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco/cascade_rcnn_hrnetv2p_w18_20e_coco_20200210-434be9d7.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco/cascade_rcnn_hrnetv2p_w18_20e_coco_20200210_105632.log.json) | +| HRNetV2p-W32 | pytorch | 20e | 9.4 | 11.0 | 43.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco/cascade_rcnn_hrnetv2p_w32_20e_coco_20200208-928455a4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco/cascade_rcnn_hrnetv2p_w32_20e_coco_20200208_160511.log.json) | +| HRNetV2p-W40 | pytorch | 20e | 10.8 | | 43.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco/cascade_rcnn_hrnetv2p_w40_20e_coco_20200512_161112-75e47b04.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco/cascade_rcnn_hrnetv2p_w40_20e_coco_20200512_161112.log.json) | + +### Cascade Mask R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :-------------:|:------:| :------:|:------:|:--------:| +| HRNetV2p-W18 | pytorch | 20e | 8.5 | 8.5 |41.6 |36.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco/cascade_mask_rcnn_hrnetv2p_w18_20e_coco_20200210-b543cd2b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco/cascade_mask_rcnn_hrnetv2p_w18_20e_coco_20200210_093149.log.json) | +| HRNetV2p-W32 | pytorch | 20e | | 8.3 |44.3 |38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco/cascade_mask_rcnn_hrnetv2p_w32_20e_coco_20200512_154043-39d9cf7b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco/cascade_mask_rcnn_hrnetv2p_w32_20e_coco_20200512_154043.log.json) | +| HRNetV2p-W40 | pytorch | 20e | 12.5 | |45.1 |39.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco/cascade_mask_rcnn_hrnetv2p_w40_20e_coco_20200527_204922-969c4610.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco/cascade_mask_rcnn_hrnetv2p_w40_20e_coco_20200527_204922.log.json) | + +### Hybrid Task Cascade (HTC) + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :-------------:|:------:| :------:|:------:|:--------:| +| HRNetV2p-W18 | pytorch | 20e | 10.8 | 4.7 | 42.8 | 37.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/htc_hrnetv2p_w18_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w18_20e_coco/htc_hrnetv2p_w18_20e_coco_20200210-b266988c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w18_20e_coco/htc_hrnetv2p_w18_20e_coco_20200210_182735.log.json) | +| HRNetV2p-W32 | pytorch | 20e | 13.1 | 4.9 | 45.4 | 39.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/htc_hrnetv2p_w32_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w32_20e_coco/htc_hrnetv2p_w32_20e_coco_20200207-7639fa12.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w32_20e_coco/htc_hrnetv2p_w32_20e_coco_20200207_193153.log.json) | +| HRNetV2p-W40 | pytorch | 20e | 14.6 | | 46.4 | 40.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/htc_hrnetv2p_w40_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w40_20e_coco/htc_hrnetv2p_w40_20e_coco_20200529_183411-417c4d5b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w40_20e_coco/htc_hrnetv2p_w40_20e_coco_20200529_183411.log.json) | + +### FCOS + +| Backbone | Style | GN | MS train | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:-------:|:------:|:------:|:------:|:------:|:--------:| +|HRNetV2p-W18| pytorch | Y | N | 1x | 13.0 | 12.9 | 35.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco_20201212_100710-4ad151de.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco_20201212_100710.log.json) | +|HRNetV2p-W18| pytorch | Y | N | 2x | 13.0 | - | 38.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco_20201212_101110-5c575fa5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco_20201212_101110.log.json) | +|HRNetV2p-W32| pytorch | Y | N | 1x | 17.5 | 12.9 | 39.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco_20201211_134730-cb8055c0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco_20201211_134730.log.json) | +|HRNetV2p-W32| pytorch | Y | N | 2x | 17.5 | - | 40.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco_20201212_112133-77b6b9bb.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco_20201212_112133.log.json) | +|HRNetV2p-W18| pytorch | Y | Y | 2x | 13.0 | 12.9 | 38.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco_20201212_111651-441e9d9f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco_20201212_111651.log.json) | +|HRNetV2p-W32| pytorch | Y | Y | 2x | 17.5 | 12.4 | 41.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco_20201212_090846-b6f2b49f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco_20201212_090846.log.json) | +|HRNetV2p-W48| pytorch | Y | Y | 2x | 20.3 | 10.8 | 42.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco_20201212_124752-f22d2ce5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco_20201212_124752.log.json) | + +**Note:** + +- The `28e` schedule in HTC indicates decreasing the lr at 24 and 27 epochs, with a total of 28 epochs. +- HRNetV2 ImageNet pretrained models are in [HRNets for Image Classification](https://github.com/HRNet/HRNet-Image-Classification). diff --git a/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py b/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py new file mode 100644 index 0000000..839cf3e --- /dev/null +++ b/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py @@ -0,0 +1,11 @@ +_base_ = './cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py' +# model settings +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py b/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py new file mode 100644 index 0000000..9942602 --- /dev/null +++ b/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py @@ -0,0 +1,40 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + _delete_=True, + type='HRNet', + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')), + neck=dict( + _delete_=True, + type='HRFPN', + in_channels=[32, 64, 128, 256], + out_channels=256)) +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py b/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py new file mode 100644 index 0000000..10d5e83 --- /dev/null +++ b/configs/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py @@ -0,0 +1,12 @@ +_base_ = './cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py' +# model settings +model = dict( + backbone=dict( + type='HRNet', + extra=dict( + stage2=dict(num_channels=(40, 80)), + stage3=dict(num_channels=(40, 80, 160)), + stage4=dict(num_channels=(40, 80, 160, 320))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w40')), + neck=dict(type='HRFPN', in_channels=[40, 80, 160, 320], out_channels=256)) diff --git a/configs/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco.py b/configs/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco.py new file mode 100644 index 0000000..ebd5e20 --- /dev/null +++ b/configs/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco.py @@ -0,0 +1,11 @@ +_base_ = './cascade_rcnn_hrnetv2p_w32_20e_coco.py' +# model settings +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco.py b/configs/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco.py new file mode 100644 index 0000000..e7f89a9 --- /dev/null +++ b/configs/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco.py @@ -0,0 +1,40 @@ +_base_ = '../cascade_rcnn/cascade_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + _delete_=True, + type='HRNet', + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')), + neck=dict( + _delete_=True, + type='HRFPN', + in_channels=[32, 64, 128, 256], + out_channels=256)) +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco.py b/configs/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco.py new file mode 100644 index 0000000..265e8d6 --- /dev/null +++ b/configs/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco.py @@ -0,0 +1,12 @@ +_base_ = './cascade_rcnn_hrnetv2p_w32_20e_coco.py' +# model settings +model = dict( + backbone=dict( + type='HRNet', + extra=dict( + stage2=dict(num_channels=(40, 80)), + stage3=dict(num_channels=(40, 80, 160)), + stage4=dict(num_channels=(40, 80, 160, 320))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w40')), + neck=dict(type='HRFPN', in_channels=[40, 80, 160, 320], out_channels=256)) diff --git a/configs/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py b/configs/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py new file mode 100644 index 0000000..1df2c3d --- /dev/null +++ b/configs/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = './faster_rcnn_hrnetv2p_w32_1x_coco.py' +# model settings +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py b/configs/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py new file mode 100644 index 0000000..a4b987a --- /dev/null +++ b/configs/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py @@ -0,0 +1,5 @@ +_base_ = './faster_rcnn_hrnetv2p_w18_1x_coco.py' + +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py b/configs/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py new file mode 100644 index 0000000..be05809 --- /dev/null +++ b/configs/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py @@ -0,0 +1,37 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + _delete_=True, + type='HRNet', + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')), + neck=dict( + _delete_=True, + type='HRFPN', + in_channels=[32, 64, 128, 256], + out_channels=256)) diff --git a/configs/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py b/configs/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py new file mode 100644 index 0000000..63c8717 --- /dev/null +++ b/configs/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './faster_rcnn_hrnetv2p_w32_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py b/configs/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py new file mode 100644 index 0000000..886a7c9 --- /dev/null +++ b/configs/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = './faster_rcnn_hrnetv2p_w32_1x_coco.py' +model = dict( + backbone=dict( + type='HRNet', + extra=dict( + stage2=dict(num_channels=(40, 80)), + stage3=dict(num_channels=(40, 80, 160)), + stage4=dict(num_channels=(40, 80, 160, 320))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w40')), + neck=dict(type='HRFPN', in_channels=[40, 80, 160, 320], out_channels=256)) diff --git a/configs/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py b/configs/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py new file mode 100644 index 0000000..585cc2c --- /dev/null +++ b/configs/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './faster_rcnn_hrnetv2p_w40_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py b/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py new file mode 100644 index 0000000..fd662bd --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py @@ -0,0 +1,10 @@ +_base_ = './fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py' +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py b/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py new file mode 100644 index 0000000..3497595 --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco.py b/configs/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco.py new file mode 100644 index 0000000..37bfdae --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco.py @@ -0,0 +1,10 @@ +_base_ = './fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py' +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py b/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py new file mode 100644 index 0000000..10617f2 --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py @@ -0,0 +1,70 @@ +_base_ = '../fcos/fcos_r50_caffe_fpn_gn-head_4x4_1x_coco.py' +model = dict( + backbone=dict( + _delete_=True, + type='HRNet', + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')), + neck=dict( + _delete_=True, + type='HRFPN', + in_channels=[32, 64, 128, 256], + out_channels=256, + stride=2, + num_outs=5)) +img_norm_cfg = dict( + mean=[103.53, 116.28, 123.675], std=[57.375, 57.12, 58.395], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py b/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py new file mode 100644 index 0000000..7b38130 --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py b/configs/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py new file mode 100644 index 0000000..482f887 --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py @@ -0,0 +1,39 @@ +_base_ = './fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py' +img_norm_cfg = dict( + mean=[103.53, 116.28, 123.675], std=[57.375, 57.12, 58.395], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco.py b/configs/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco.py new file mode 100644 index 0000000..0ae9dbe --- /dev/null +++ b/configs/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco.py @@ -0,0 +1,11 @@ +_base_ = './fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py' +model = dict( + backbone=dict( + type='HRNet', + extra=dict( + stage2=dict(num_channels=(40, 80)), + stage3=dict(num_channels=(40, 80, 160)), + stage4=dict(num_channels=(40, 80, 160, 320))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w40')), + neck=dict(type='HRFPN', in_channels=[40, 80, 160, 320], out_channels=256)) diff --git a/configs/hrnet/htc_hrnetv2p_w18_20e_coco.py b/configs/hrnet/htc_hrnetv2p_w18_20e_coco.py new file mode 100644 index 0000000..3c2eb1d --- /dev/null +++ b/configs/hrnet/htc_hrnetv2p_w18_20e_coco.py @@ -0,0 +1,10 @@ +_base_ = './htc_hrnetv2p_w32_20e_coco.py' +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/htc_hrnetv2p_w32_20e_coco.py b/configs/hrnet/htc_hrnetv2p_w32_20e_coco.py new file mode 100644 index 0000000..545cb83 --- /dev/null +++ b/configs/hrnet/htc_hrnetv2p_w32_20e_coco.py @@ -0,0 +1,37 @@ +_base_ = '../htc/htc_r50_fpn_20e_coco.py' +model = dict( + backbone=dict( + _delete_=True, + type='HRNet', + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')), + neck=dict( + _delete_=True, + type='HRFPN', + in_channels=[32, 64, 128, 256], + out_channels=256)) diff --git a/configs/hrnet/htc_hrnetv2p_w40_20e_coco.py b/configs/hrnet/htc_hrnetv2p_w40_20e_coco.py new file mode 100644 index 0000000..94bff1b --- /dev/null +++ b/configs/hrnet/htc_hrnetv2p_w40_20e_coco.py @@ -0,0 +1,11 @@ +_base_ = './htc_hrnetv2p_w32_20e_coco.py' +model = dict( + backbone=dict( + type='HRNet', + extra=dict( + stage2=dict(num_channels=(40, 80)), + stage3=dict(num_channels=(40, 80, 160)), + stage4=dict(num_channels=(40, 80, 160, 320))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w40')), + neck=dict(type='HRFPN', in_channels=[40, 80, 160, 320], out_channels=256)) diff --git a/configs/hrnet/htc_hrnetv2p_w40_28e_coco.py b/configs/hrnet/htc_hrnetv2p_w40_28e_coco.py new file mode 100644 index 0000000..7067e8b --- /dev/null +++ b/configs/hrnet/htc_hrnetv2p_w40_28e_coco.py @@ -0,0 +1,4 @@ +_base_ = './htc_hrnetv2p_w40_20e_coco.py' +# learning policy +lr_config = dict(step=[24, 27]) +runner = dict(type='EpochBasedRunner', max_epochs=28) diff --git a/configs/hrnet/htc_x101_64x4d_fpn_16x1_28e_coco.py b/configs/hrnet/htc_x101_64x4d_fpn_16x1_28e_coco.py new file mode 100644 index 0000000..815f285 --- /dev/null +++ b/configs/hrnet/htc_x101_64x4d_fpn_16x1_28e_coco.py @@ -0,0 +1,4 @@ +_base_ = '../htc/htc_x101_64x4d_fpn_16x1_20e_coco.py' +# learning policy +lr_config = dict(step=[24, 27]) +runner = dict(type='EpochBasedRunner', max_epochs=28) diff --git a/configs/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py b/configs/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py new file mode 100644 index 0000000..cb12200 --- /dev/null +++ b/configs/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py @@ -0,0 +1,10 @@ +_base_ = './mask_rcnn_hrnetv2p_w32_1x_coco.py' +model = dict( + backbone=dict( + extra=dict( + stage2=dict(num_channels=(18, 36)), + stage3=dict(num_channels=(18, 36, 72)), + stage4=dict(num_channels=(18, 36, 72, 144))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18')), + neck=dict(type='HRFPN', in_channels=[18, 36, 72, 144], out_channels=256)) diff --git a/configs/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py b/configs/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py new file mode 100644 index 0000000..ca62682 --- /dev/null +++ b/configs/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_hrnetv2p_w18_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py b/configs/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py new file mode 100644 index 0000000..d5f0eb5 --- /dev/null +++ b/configs/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py @@ -0,0 +1,37 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + _delete_=True, + type='HRNet', + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w32')), + neck=dict( + _delete_=True, + type='HRFPN', + in_channels=[32, 64, 128, 256], + out_channels=256)) diff --git a/configs/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py b/configs/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py new file mode 100644 index 0000000..63d5d13 --- /dev/null +++ b/configs/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_hrnetv2p_w32_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py b/configs/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py new file mode 100644 index 0000000..5a76f4b --- /dev/null +++ b/configs/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py @@ -0,0 +1,11 @@ +_base_ = './mask_rcnn_hrnetv2p_w18_1x_coco.py' +model = dict( + backbone=dict( + type='HRNet', + extra=dict( + stage2=dict(num_channels=(40, 80)), + stage3=dict(num_channels=(40, 80, 160)), + stage4=dict(num_channels=(40, 80, 160, 320))), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w40')), + neck=dict(type='HRFPN', in_channels=[40, 80, 160, 320], out_channels=256)) diff --git a/configs/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py b/configs/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py new file mode 100644 index 0000000..3a2a510 --- /dev/null +++ b/configs/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_hrnetv2p_w40_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/hrnet/metafile.yml b/configs/hrnet/metafile.yml new file mode 100644 index 0000000..37703aa --- /dev/null +++ b/configs/hrnet/metafile.yml @@ -0,0 +1,604 @@ +Collections: + - Name: HRNet + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - HRNet + Paper: + URL: https://arxiv.org/abs/1904.04514 + Title: 'Deep High-Resolution Representation Learning for Visual Recognition' + README: configs/hrnet/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/backbones/hrnet.py#L195 + Version: v2.0.0 + +Models: + - Name: faster_rcnn_hrnetv2p_w18_1x_coco + In Collection: HRNet + Config: configs/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco.py + Metadata: + Training Memory (GB): 6.6 + inference time (ms/im): + - value: 74.63 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w18_1x_coco/faster_rcnn_hrnetv2p_w18_1x_coco_20200130-56651a6d.pth + + - Name: faster_rcnn_hrnetv2p_w18_2x_coco + In Collection: HRNet + Config: configs/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco.py + Metadata: + Training Memory (GB): 6.6 + inference time (ms/im): + - value: 74.63 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w18_2x_coco/faster_rcnn_hrnetv2p_w18_2x_coco_20200702_085731-a4ec0611.pth + + - Name: faster_rcnn_hrnetv2p_w32_1x_coco + In Collection: HRNet + Config: configs/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco.py + Metadata: + Training Memory (GB): 9.0 + inference time (ms/im): + - value: 80.65 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w32_1x_coco/faster_rcnn_hrnetv2p_w32_1x_coco_20200130-6e286425.pth + + - Name: faster_rcnn_hrnetv2p_w32_2x_coco + In Collection: HRNet + Config: configs/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco.py + Metadata: + Training Memory (GB): 9.0 + inference time (ms/im): + - value: 80.65 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w32_2x_coco/faster_rcnn_hrnetv2p_w32_2x_coco_20200529_015927-976a9c15.pth + + - Name: faster_rcnn_hrnetv2p_w40_1x_coco + In Collection: HRNet + Config: configs/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco.py + Metadata: + Training Memory (GB): 10.4 + inference time (ms/im): + - value: 95.24 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w40_1x_coco/faster_rcnn_hrnetv2p_w40_1x_coco_20200210-95c1f5ce.pth + + - Name: faster_rcnn_hrnetv2p_w40_2x_coco + In Collection: HRNet + Config: configs/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco.py + Metadata: + Training Memory (GB): 10.4 + inference time (ms/im): + - value: 95.24 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/faster_rcnn_hrnetv2p_w40_2x_coco/faster_rcnn_hrnetv2p_w40_2x_coco_20200512_161033-0f236ef4.pth + + - Name: mask_rcnn_hrnetv2p_w18_1x_coco + In Collection: HRNet + Config: configs/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco.py + Metadata: + Training Memory (GB): 7.0 + inference time (ms/im): + - value: 85.47 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 34.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w18_1x_coco/mask_rcnn_hrnetv2p_w18_1x_coco_20200205-1c3d78ed.pth + + - Name: mask_rcnn_hrnetv2p_w18_2x_coco + In Collection: HRNet + Config: configs/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco.py + Metadata: + Training Memory (GB): 7.0 + inference time (ms/im): + - value: 85.47 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w18_2x_coco/mask_rcnn_hrnetv2p_w18_2x_coco_20200212-b3c825b1.pth + + - Name: mask_rcnn_hrnetv2p_w32_1x_coco + In Collection: HRNet + Config: configs/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco.py + Metadata: + Training Memory (GB): 9.4 + inference time (ms/im): + - value: 88.5 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w32_1x_coco/mask_rcnn_hrnetv2p_w32_1x_coco_20200207-b29f616e.pth + + - Name: mask_rcnn_hrnetv2p_w32_2x_coco + In Collection: HRNet + Config: configs/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco.py + Metadata: + Training Memory (GB): 9.4 + inference time (ms/im): + - value: 88.5 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w32_2x_coco/mask_rcnn_hrnetv2p_w32_2x_coco_20200213-45b75b4d.pth + + - Name: mask_rcnn_hrnetv2p_w40_1x_coco + In Collection: HRNet + Config: configs/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco.py + Metadata: + Training Memory (GB): 10.9 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w40_1x_coco/mask_rcnn_hrnetv2p_w40_1x_coco_20200511_015646-66738b35.pth + + - Name: mask_rcnn_hrnetv2p_w40_2x_coco + In Collection: HRNet + Config: configs/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco.py + Metadata: + Training Memory (GB): 10.9 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/mask_rcnn_hrnetv2p_w40_2x_coco/mask_rcnn_hrnetv2p_w40_2x_coco_20200512_163732-aed5e4ab.pth + + - Name: cascade_rcnn_hrnetv2p_w18_20e_coco + In Collection: HRNet + Config: configs/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco.py + Metadata: + Training Memory (GB): 7.0 + inference time (ms/im): + - value: 90.91 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w18_20e_coco/cascade_rcnn_hrnetv2p_w18_20e_coco_20200210-434be9d7.pth + + - Name: cascade_rcnn_hrnetv2p_w32_20e_coco + In Collection: HRNet + Config: configs/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco.py + Metadata: + Training Memory (GB): 9.4 + inference time (ms/im): + - value: 90.91 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w32_20e_coco/cascade_rcnn_hrnetv2p_w32_20e_coco_20200208-928455a4.pth + + - Name: cascade_rcnn_hrnetv2p_w40_20e_coco + In Collection: HRNet + Config: configs/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco.py + Metadata: + Training Memory (GB): 10.8 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_rcnn_hrnetv2p_w40_20e_coco/cascade_rcnn_hrnetv2p_w40_20e_coco_20200512_161112-75e47b04.pth + + - Name: cascade_mask_rcnn_hrnetv2p_w18_20e_coco + In Collection: HRNet + Config: configs/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco.py + Metadata: + Training Memory (GB): 8.5 + inference time (ms/im): + - value: 117.65 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w18_20e_coco/cascade_mask_rcnn_hrnetv2p_w18_20e_coco_20200210-b543cd2b.pth + + - Name: cascade_mask_rcnn_hrnetv2p_w32_20e_coco + In Collection: HRNet + Config: configs/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco.py + Metadata: + inference time (ms/im): + - value: 120.48 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w32_20e_coco/cascade_mask_rcnn_hrnetv2p_w32_20e_coco_20200512_154043-39d9cf7b.pth + + - Name: cascade_mask_rcnn_hrnetv2p_w40_20e_coco + In Collection: HRNet + Config: configs/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco.py + Metadata: + Training Memory (GB): 12.5 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/cascade_mask_rcnn_hrnetv2p_w40_20e_coco/cascade_mask_rcnn_hrnetv2p_w40_20e_coco_20200527_204922-969c4610.pth + + - Name: htc_hrnetv2p_w18_20e_coco + In Collection: HRNet + Config: configs/hrnet/htc_hrnetv2p_w18_20e_coco.py + Metadata: + Training Memory (GB): 10.8 + inference time (ms/im): + - value: 212.77 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w18_20e_coco/htc_hrnetv2p_w18_20e_coco_20200210-b266988c.pth + + - Name: htc_hrnetv2p_w32_20e_coco + In Collection: HRNet + Config: configs/hrnet/htc_hrnetv2p_w32_20e_coco.py + Metadata: + Training Memory (GB): 13.1 + inference time (ms/im): + - value: 204.08 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w32_20e_coco/htc_hrnetv2p_w32_20e_coco_20200207-7639fa12.pth + + - Name: htc_hrnetv2p_w40_20e_coco + In Collection: HRNet + Config: configs/hrnet/htc_hrnetv2p_w40_20e_coco.py + Metadata: + Training Memory (GB): 14.6 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/htc_hrnetv2p_w40_20e_coco/htc_hrnetv2p_w40_20e_coco_20200529_183411-417c4d5b.pth + + - Name: fcos_hrnetv2p_w18_gn-head_4x4_1x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 13.0 + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 35.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco/fcos_hrnetv2p_w18_gn-head_4x4_1x_coco_20201212_100710-4ad151de.pth + + - Name: fcos_hrnetv2p_w18_gn-head_4x4_2x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 13.0 + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco/fcos_hrnetv2p_w18_gn-head_4x4_2x_coco_20201212_101110-5c575fa5.pth + + - Name: fcos_hrnetv2p_w32_gn-head_4x4_1x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 17.5 + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco/fcos_hrnetv2p_w32_gn-head_4x4_1x_coco_20201211_134730-cb8055c0.pth + + - Name: fcos_hrnetv2p_w32_gn-head_4x4_2x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 17.5 + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco/fcos_hrnetv2p_w32_gn-head_4x4_2x_coco_20201212_112133-77b6b9bb.pth + + - Name: fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 13.0 + inference time (ms/im): + - value: 77.52 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w18_gn-head_mstrain_640-800_4x4_2x_coco_20201212_111651-441e9d9f.pth + + - Name: fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 17.5 + inference time (ms/im): + - value: 80.65 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w32_gn-head_mstrain_640-800_4x4_2x_coco_20201212_090846-b6f2b49f.pth + + - Name: fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco + In Collection: HRNet + Config: configs/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco.py + Metadata: + Training Resources: 4x V100 GPUs + Batch Size: 16 + Training Memory (GB): 20.3 + inference time (ms/im): + - value: 92.59 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/hrnet/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco/fcos_hrnetv2p_w40_gn-head_mstrain_640-800_4x4_2x_coco_20201212_124752-f22d2ce5.pth diff --git a/configs/htc/README.md b/configs/htc/README.md new file mode 100644 index 0000000..1625827 --- /dev/null +++ b/configs/htc/README.md @@ -0,0 +1,57 @@ +# Hybrid Task Cascade for Instance Segmentation + +## Introduction + + + +We provide config files to reproduce the results in the CVPR 2019 paper for [Hybrid Task Cascade](https://arxiv.org/abs/1901.07518). + +```latex +@inproceedings{chen2019hybrid, + title={Hybrid task cascade for instance segmentation}, + author={Chen, Kai and Pang, Jiangmiao and Wang, Jiaqi and Xiong, Yu and Li, Xiaoxiao and Sun, Shuyang and Feng, Wansen and Liu, Ziwei and Shi, Jianping and Ouyang, Wanli and Chen Change Loy and Dahua Lin}, + booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, + year={2019} +} +``` + +## Dataset + +HTC requires COCO and [COCO-stuff](http://calvin.inf.ed.ac.uk/wp-content/uploads/data/cocostuffdataset/stuffthingmaps_trainval2017.zip) dataset for training. You need to download and extract it in the COCO dataset path. +The directory should be like this. + +```none +mmdetection +├── mmdet +├── tools +├── configs +├── data +│ ├── coco +│ │ ├── annotations +│ │ ├── train2017 +│ │ ├── val2017 +│ │ ├── test2017 +| | ├── stuffthingmaps +``` + +## Results and Models + +The results on COCO 2017val are shown in the below table. (results on test-dev are usually slightly higher than val) + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:---------:|:-------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN | pytorch | 1x | 8.2 | 5.8 | 42.3 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/htc/htc_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r50_fpn_1x_coco/htc_r50_fpn_1x_coco_20200317-7332cf16.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r50_fpn_1x_coco/htc_r50_fpn_1x_coco_20200317_070435.log.json) | +| R-50-FPN | pytorch | 20e | 8.2 | - | 43.3 | 38.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/htc/htc_r50_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r50_fpn_20e_coco/htc_r50_fpn_20e_coco_20200319-fe28c577.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r50_fpn_20e_coco/htc_r50_fpn_20e_coco_20200319_070313.log.json) | +| R-101-FPN | pytorch | 20e | 10.2 | 5.5 | 44.8 | 39.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/htc/htc_r101_fpn_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r101_fpn_20e_coco/htc_r101_fpn_20e_coco_20200317-9b41b48f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r101_fpn_20e_coco/htc_r101_fpn_20e_coco_20200317_153107.log.json) | +| X-101-32x4d-FPN | pytorch |20e| 11.4 | 5.0 | 46.1 | 40.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/htc/htc_x101_32x4d_fpn_16x1_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_32x4d_fpn_16x1_20e_coco/htc_x101_32x4d_fpn_16x1_20e_coco_20200318-de97ae01.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_32x4d_fpn_16x1_20e_coco/htc_x101_32x4d_fpn_16x1_20e_coco_20200318_034519.log.json) | +| X-101-64x4d-FPN | pytorch |20e| 14.5 | 4.4 | 47.0 | 41.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/htc/htc_x101_64x4d_fpn_16x1_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_64x4d_fpn_16x1_20e_coco/htc_x101_64x4d_fpn_16x1_20e_coco_20200318-b181fd7a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_64x4d_fpn_16x1_20e_coco/htc_x101_64x4d_fpn_16x1_20e_coco_20200318_081711.log.json) | + +- In the HTC paper and COCO 2018 Challenge, `score_thr` is set to 0.001 for both baselines and HTC. +- We use 8 GPUs with 2 images/GPU for R-50 and R-101 models, and 16 GPUs with 1 image/GPU for X-101 models. + If you would like to train X-101 HTC with 8 GPUs, you need to change the lr from 0.02 to 0.01. + +We also provide a powerful HTC with DCN and multi-scale training model. No testing augmentation is used. + +| Backbone | Style | DCN | training scales | Lr schd | box AP | mask AP | Config | Download | +|:----------------:|:-------:|:-----:|:---------------:|:-------:|:------:|:-------:|:------:|:--------:| +| X-101-64x4d-FPN | pytorch | c3-c5 | 400~1400 | 20e | 50.4 | 43.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco_20200312-946fd751.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco_20200312_203410.log.json) | diff --git a/configs/htc/htc_r101_fpn_20e_coco.py b/configs/htc/htc_r101_fpn_20e_coco.py new file mode 100644 index 0000000..b42297b --- /dev/null +++ b/configs/htc/htc_r101_fpn_20e_coco.py @@ -0,0 +1,9 @@ +_base_ = './htc_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/htc/htc_r50_fpn_1x_coco.py b/configs/htc/htc_r50_fpn_1x_coco.py new file mode 100644 index 0000000..1e8e18a --- /dev/null +++ b/configs/htc/htc_r50_fpn_1x_coco.py @@ -0,0 +1,56 @@ +_base_ = './htc_without_semantic_r50_fpn_1x_coco.py' +model = dict( + roi_head=dict( + semantic_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=256, + featmap_strides=[8]), + semantic_head=dict( + type='FusedSemanticHead', + num_ins=5, + fusion_level=1, + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=183, + loss_seg=dict( + type='CrossEntropyLoss', ignore_index=255, loss_weight=0.2)))) +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) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', with_bbox=True, with_mask=True, with_seg=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='SegRescale', scale_factor=1 / 8), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks', 'gt_semantic_seg']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + train=dict( + seg_prefix=data_root + 'stuffthingmaps/train2017/', + pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/htc/htc_r50_fpn_20e_coco.py b/configs/htc/htc_r50_fpn_20e_coco.py new file mode 100644 index 0000000..7d2e011 --- /dev/null +++ b/configs/htc/htc_r50_fpn_20e_coco.py @@ -0,0 +1,4 @@ +_base_ = './htc_r50_fpn_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/htc/htc_without_semantic_r50_fpn_1x_coco.py b/configs/htc/htc_without_semantic_r50_fpn_1x_coco.py new file mode 100644 index 0000000..565104f --- /dev/null +++ b/configs/htc/htc_without_semantic_r50_fpn_1x_coco.py @@ -0,0 +1,236 @@ +_base_ = [ + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# model settings +model = dict( + type='HybridTaskCascade', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + type='HybridTaskCascadeRoIHead', + interleaved=True, + mask_info_flow=True, + num_stages=3, + stage_loss_weights=[1, 0.5, 0.25], + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=[ + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, + loss_weight=1.0)), + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.05, 0.05, 0.1, 0.1]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, + loss_weight=1.0)), + dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.033, 0.033, 0.067, 0.067]), + reg_class_agnostic=True, + loss_cls=dict( + type='CrossEntropyLoss', + use_sigmoid=False, + loss_weight=1.0), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)) + ], + mask_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + mask_head=[ + dict( + type='HTCMaskHead', + with_conv_res=False, + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0)), + dict( + type='HTCMaskHead', + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0)), + dict( + type='HTCMaskHead', + num_convs=4, + in_channels=256, + conv_out_channels=256, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0)) + ]), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=0, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=[ + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.6, + neg_iou_thr=0.6, + min_pos_iou=0.6, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False), + dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.7, + min_pos_iou=0.7, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + mask_size=28, + pos_weight=-1, + debug=False) + ]), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.001, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100, + mask_thr_binary=0.5))) +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + val=dict(pipeline=test_pipeline), test=dict(pipeline=test_pipeline)) diff --git a/configs/htc/htc_x101_32x4d_fpn_16x1_20e_coco.py b/configs/htc/htc_x101_32x4d_fpn_16x1_20e_coco.py new file mode 100644 index 0000000..0c834f2 --- /dev/null +++ b/configs/htc/htc_x101_32x4d_fpn_16x1_20e_coco.py @@ -0,0 +1,19 @@ +_base_ = './htc_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) +data = dict(samples_per_gpu=1, workers_per_gpu=1) +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/htc/htc_x101_64x4d_fpn_16x1_20e_coco.py b/configs/htc/htc_x101_64x4d_fpn_16x1_20e_coco.py new file mode 100644 index 0000000..8b0d962 --- /dev/null +++ b/configs/htc/htc_x101_64x4d_fpn_16x1_20e_coco.py @@ -0,0 +1,19 @@ +_base_ = './htc_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) +data = dict(samples_per_gpu=1, workers_per_gpu=1) +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco.py b/configs/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco.py new file mode 100644 index 0000000..c8d8703 --- /dev/null +++ b/configs/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco.py @@ -0,0 +1,43 @@ +_base_ = './htc_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + dcn=dict(type='DCN', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) +# dataset settings +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, with_mask=True, with_seg=True), + dict( + type='Resize', + img_scale=[(1600, 400), (1600, 1400)], + multiscale_mode='range', + keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='SegRescale', scale_factor=1 / 8), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks', 'gt_semantic_seg']), +] +data = dict( + samples_per_gpu=1, workers_per_gpu=1, train=dict(pipeline=train_pipeline)) +# learning policy +lr_config = dict(step=[16, 19]) +runner = dict(type='EpochBasedRunner', max_epochs=20) diff --git a/configs/htc/metafile.yml b/configs/htc/metafile.yml new file mode 100644 index 0000000..acd038c --- /dev/null +++ b/configs/htc/metafile.yml @@ -0,0 +1,165 @@ +Collections: + - Name: HTC + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - HTC + - RPN + - ResNet + - ResNeXt + - RoIAlign + Paper: + URL: https://arxiv.org/abs/1901.07518 + Title: 'Hybrid Task Cascade for Instance Segmentation' + README: configs/htc/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/htc.py#L6 + Version: v2.0.0 + +Models: + - Name: htc_r50_fpn_1x_coco + In Collection: HTC + Config: configs/htc/htc_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 8.2 + inference time (ms/im): + - value: 172.41 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r50_fpn_1x_coco/htc_r50_fpn_1x_coco_20200317-7332cf16.pth + + - Name: htc_r50_fpn_20e_coco + In Collection: HTC + Config: configs/htc/htc_r50_fpn_20e_coco.py + Metadata: + Training Memory (GB): 8.2 + inference time (ms/im): + - value: 172.41 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r50_fpn_20e_coco/htc_r50_fpn_20e_coco_20200319-fe28c577.pth + + - Name: htc_r101_fpn_20e_coco + In Collection: HTC + Config: configs/htc/htc_r101_fpn_20e_coco.py + Metadata: + Training Memory (GB): 10.2 + inference time (ms/im): + - value: 181.82 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/htc/htc_r101_fpn_20e_coco/htc_r101_fpn_20e_coco_20200317-9b41b48f.pth + + - Name: htc_x101_32x4d_fpn_16x1_20e_coco + In Collection: HTC + Config: configs/htc/htc_x101_32x4d_fpn_16x1_20e_coco.py + Metadata: + Training Resources: 16x V100 GPUs + Batch Size: 16 + Training Memory (GB): 11.4 + inference time (ms/im): + - value: 200 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_32x4d_fpn_16x1_20e_coco/htc_x101_32x4d_fpn_16x1_20e_coco_20200318-de97ae01.pth + + - Name: htc_x101_64x4d_fpn_16x1_20e_coco + In Collection: HTC + Config: configs/htc/htc_x101_64x4d_fpn_16x1_20e_coco.py + Metadata: + Training Resources: 16x V100 GPUs + Batch Size: 16 + Training Memory (GB): 14.5 + inference time (ms/im): + - value: 227.27 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 41.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_64x4d_fpn_16x1_20e_coco/htc_x101_64x4d_fpn_16x1_20e_coco_20200318-b181fd7a.pth + + - Name: htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco + In Collection: HTC + Config: configs/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco.py + Metadata: + Training Resources: 16x V100 GPUs + Batch Size: 16 + Epochs: 20 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 50.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 43.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/htc/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco/htc_x101_64x4d_fpn_dconv_c3-c5_mstrain_400_1400_16x1_20e_coco_20200312-946fd751.pth diff --git a/configs/instaboost/README.md b/configs/instaboost/README.md new file mode 100644 index 0000000..6d365ac --- /dev/null +++ b/configs/instaboost/README.md @@ -0,0 +1,44 @@ +# InstaBoost for MMDetection + + + +Configs in this directory is the implementation for ICCV2019 paper "InstaBoost: Boosting Instance Segmentation Via Probability Map Guided Copy-Pasting" and provided by the authors of the paper. InstaBoost is a data augmentation method for object detection and instance segmentation. The paper has been released on [`arXiv`](https://arxiv.org/abs/1908.07801). + +```latex +@inproceedings{fang2019instaboost, + title={Instaboost: Boosting instance segmentation via probability map guided copy-pasting}, + author={Fang, Hao-Shu and Sun, Jianhua and Wang, Runzhong and Gou, Minghao and Li, Yong-Lu and Lu, Cewu}, + booktitle={Proceedings of the IEEE International Conference on Computer Vision}, + pages={682--691}, + year={2019} +} +``` + +## Usage + +### Requirements + +You need to install `instaboostfast` before using it. + +```shell +pip install instaboostfast +``` + +The code and more details can be found [here](https://github.com/GothicAi/Instaboost). + +### Integration with MMDetection + +InstaBoost have been already integrated in the data pipeline, thus all you need is to add or change **InstaBoost** configurations after **LoadImageFromFile**. We have provided examples like [this](mask_rcnn_r50_fpn_instaboost_4x#L121). You can refer to [`InstaBoostConfig`](https://github.com/GothicAi/InstaBoost-pypi#instaboostconfig) for more details. + +## Results and Models + +- All models were trained on `coco_2017_train` and tested on `coco_2017_val` for convenience of evaluation and comparison. In the paper, the results are obtained from `test-dev`. +- To balance accuracy and training time when using InstaBoost, models released in this page are all trained for 48 Epochs. Other training and testing configs strictly follow the original framework. +- For results and models in MMDetection V1.x, please refer to [Instaboost](https://github.com/GothicAi/Instaboost). + +| Network | Backbone | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :--------: | :-----: | :------: | :------------: | :------:| :-----: | :------: | :-----------------: | +| Mask R-CNN | R-50-FPN | 4x | 4.4 | 17.5 | 40.6 | 36.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco/mask_rcnn_r50_fpn_instaboost_4x_coco_20200307-d025f83a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco/mask_rcnn_r50_fpn_instaboost_4x_coco_20200307_223635.log.json) | +| Mask R-CNN | R-101-FPN | 4x | 6.4 | | 42.5 | 38.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco/mask_rcnn_r101_fpn_instaboost_4x_coco_20200703_235738-f23f3a5f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco/mask_rcnn_r101_fpn_instaboost_4x_coco_20200703_235738.log.json) | +| Mask R-CNN | X-101-64x4d-FPN | 4x | 10.7 | | 44.7 | 39.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco_20200515_080947-8ed58c1b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco_20200515_080947.log.json) | +| Cascade R-CNN | R-101-FPN | 4x | 6.0 | 12.0 | 43.7 | 38.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco_20200307-c19d98d9.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco_20200307_223646.log.json) | diff --git a/configs/instaboost/cascade_mask_rcnn_r101_fpn_instaboost_4x_coco.py b/configs/instaboost/cascade_mask_rcnn_r101_fpn_instaboost_4x_coco.py new file mode 100644 index 0000000..9d0515d --- /dev/null +++ b/configs/instaboost/cascade_mask_rcnn_r101_fpn_instaboost_4x_coco.py @@ -0,0 +1,7 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py' + +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py b/configs/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py new file mode 100644 index 0000000..a89a81f --- /dev/null +++ b/configs/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py @@ -0,0 +1,28 @@ +_base_ = '../cascade_rcnn/cascade_mask_rcnn_r50_fpn_1x_coco.py' +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='InstaBoost', + action_candidate=('normal', 'horizontal', 'skip'), + action_prob=(1, 0, 0), + scale=(0.8, 1.2), + dx=15, + dy=15, + theta=(-1, 1), + color_prob=0.5, + hflag=False, + aug_ratio=0.5), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +data = dict(train=dict(pipeline=train_pipeline)) +# learning policy +lr_config = dict(step=[32, 44]) +runner = dict(type='EpochBasedRunner', max_epochs=48) diff --git a/configs/instaboost/cascade_mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py b/configs/instaboost/cascade_mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py new file mode 100644 index 0000000..d67b799 --- /dev/null +++ b/configs/instaboost/cascade_mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py @@ -0,0 +1,14 @@ +_base_ = './cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco.py b/configs/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco.py new file mode 100644 index 0000000..ebbb43e --- /dev/null +++ b/configs/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco.py @@ -0,0 +1,6 @@ +_base_ = './mask_rcnn_r50_fpn_instaboost_4x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco.py b/configs/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco.py new file mode 100644 index 0000000..55ca62b --- /dev/null +++ b/configs/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco.py @@ -0,0 +1,28 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +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='InstaBoost', + action_candidate=('normal', 'horizontal', 'skip'), + action_prob=(1, 0, 0), + scale=(0.8, 1.2), + dx=15, + dy=15, + theta=(-1, 1), + color_prob=0.5, + hflag=False, + aug_ratio=0.5), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +data = dict(train=dict(pipeline=train_pipeline)) +# learning policy +lr_config = dict(step=[32, 44]) +runner = dict(type='EpochBasedRunner', max_epochs=48) diff --git a/configs/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py b/configs/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py new file mode 100644 index 0000000..2010f44 --- /dev/null +++ b/configs/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r50_fpn_instaboost_4x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/instaboost/metafile.yml b/configs/instaboost/metafile.yml new file mode 100644 index 0000000..325283d --- /dev/null +++ b/configs/instaboost/metafile.yml @@ -0,0 +1,99 @@ +Collections: + - Name: InstaBoost + Metadata: + Training Data: COCO + Training Techniques: + - InstaBoost + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Paper: + URL: https://arxiv.org/abs/1908.07801 + Title: 'Instaboost: Boosting instance segmentation via probability map guided copy-pasting' + README: configs/instaboost/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/datasets/pipelines/instaboost.py#L7 + Version: v2.0.0 + +Models: + - Name: mask_rcnn_r50_fpn_instaboost_4x_coco + In Collection: InstaBoost + Config: configs/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco.py + Metadata: + Training Memory (GB): 4.4 + inference time (ms/im): + - value: 57.14 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 48 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_r50_fpn_instaboost_4x_coco/mask_rcnn_r50_fpn_instaboost_4x_coco_20200307-d025f83a.pth + + - Name: mask_rcnn_r101_fpn_instaboost_4x_coco + In Collection: InstaBoost + Config: configs/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco.py + Metadata: + Training Memory (GB): 6.4 + Epochs: 48 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_r101_fpn_instaboost_4x_coco/mask_rcnn_r101_fpn_instaboost_4x_coco_20200703_235738-f23f3a5f.pth + + - Name: mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco + In Collection: InstaBoost + Config: configs/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco.py + Metadata: + Training Memory (GB): 10.7 + Epochs: 48 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/instaboost/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco/mask_rcnn_x101_64x4d_fpn_instaboost_4x_coco_20200515_080947-8ed58c1b.pth + + - Name: cascade_mask_rcnn_r50_fpn_instaboost_4x_coco + In Collection: InstaBoost + Config: configs/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco.py + Metadata: + Training Memory (GB): 6.0 + inference time (ms/im): + - value: 83.33 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 48 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/instaboost/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco/cascade_mask_rcnn_r50_fpn_instaboost_4x_coco_20200307-c19d98d9.pth diff --git a/configs/ld/README.md b/configs/ld/README.md new file mode 100644 index 0000000..0177f1e --- /dev/null +++ b/configs/ld/README.md @@ -0,0 +1,31 @@ +# Localization Distillation for Object Detection + +## Introduction + + + +```latex +@Article{zheng2021LD, + title={Localization Distillation for Object Detection}, + author= {Zhaohui Zheng, Rongguang Ye, Ping Wang, Jun Wang, Dongwei Ren, Wangmeng Zuo}, + journal={arXiv:2102.12252}, + year={2021} +} +``` + +### GFocalV1 with LD + +| Teacher | Student | Training schedule | Mini-batch size | AP (val) | AP50 (val) | AP75 (val) | Config | +| :-------: | :-----: | :---------------: | :-------------: | :------: | :--------: | :--------: | :--------------: | +| -- | R-18 | 1x | 6 | 35.8 | 53.1 | 38.2 | | +| R-101 | R-18 | 1x | 6 | 36.5 | 52.9 | 39.3 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py) | +| -- | R-34 | 1x | 6 | 38.9 | 56.6 | 42.2 | | +| R-101 | R-34 | 1x | 6 | 39.8 | 56.6 | 43.1 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py) | +| -- | R-50 | 1x | 6 | 40.1 | 58.2 | 43.1 | | +| R-101 | R-50 | 1x | 6 | 41.1 | 58.7 | 44.9 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py) | +| -- | R-101 | 2x | 6 | 44.6 | 62.9 | 48.4 | | +| R-101-DCN | R-101 | 2x | 6 | 45.4 | 63.1 | 49.5 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/ld/ld_r101_gflv1_r101dcn_fpn_coco_1x.py) | + +## Note + +- Meaning of Config name: ld_r18(student model)_gflv1(based on gflv1)_r101(teacher model)_fpn(neck)_coco(dataset)_1x(12 epoch).py diff --git a/configs/ld/ld_r101_gflv1_r101dcn_fpn_coco_2x.py b/configs/ld/ld_r101_gflv1_r101dcn_fpn_coco_2x.py new file mode 100644 index 0000000..1cbdb4c --- /dev/null +++ b/configs/ld/ld_r101_gflv1_r101dcn_fpn_coco_2x.py @@ -0,0 +1,44 @@ +_base_ = ['./ld_r18_gflv1_r101_fpn_coco_1x.py'] +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco_20200630_102002-134b07df.pth' # noqa +model = dict( + teacher_config='configs/gfl/gfl_r101_fpn_dconv_c3-c5_mstrain_2x_coco.py', + teacher_ckpt=teacher_ckpt, + backbone=dict( + type='ResNet', + depth=101, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5)) + +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) +# multi-scale training +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=[(1333, 480), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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']), +] +data = dict(train=dict(pipeline=train_pipeline)) diff --git a/configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py b/configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py new file mode 100644 index 0000000..18dce81 --- /dev/null +++ b/configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py @@ -0,0 +1,62 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth' # noqa +model = dict( + type='KnowledgeDistillationSingleStageDetector', + teacher_config='configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py', + teacher_ckpt=teacher_ckpt, + backbone=dict( + type='ResNet', + depth=18, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet18')), + neck=dict( + type='FPN', + in_channels=[64, 128, 256, 512], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5), + bbox_head=dict( + type='LDHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + octave_base_scale=8, + scales_per_octave=1, + strides=[8, 16, 32, 64, 128]), + loss_cls=dict( + type='QualityFocalLoss', + use_sigmoid=True, + beta=2.0, + loss_weight=1.0), + loss_dfl=dict(type='DistributionFocalLoss', loss_weight=0.25), + loss_ld=dict( + type='KnowledgeDistillationKLDivLoss', loss_weight=0.25, T=10), + reg_max=16, + loss_bbox=dict(type='GIoULoss', loss_weight=2.0)), + # training and testing settings + train_cfg=dict( + assigner=dict(type='ATSSAssigner', topk=9), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) + +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py b/configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py new file mode 100644 index 0000000..3b6996d --- /dev/null +++ b/configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py @@ -0,0 +1,19 @@ +_base_ = ['./ld_r18_gflv1_r101_fpn_coco_1x.py'] +model = dict( + backbone=dict( + type='ResNet', + depth=34, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet34')), + neck=dict( + type='FPN', + in_channels=[64, 128, 256, 512], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5)) diff --git a/configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py b/configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py new file mode 100644 index 0000000..2b18785 --- /dev/null +++ b/configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py @@ -0,0 +1,19 @@ +_base_ = ['./ld_r18_gflv1_r101_fpn_coco_1x.py'] +model = dict( + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5)) diff --git a/configs/ld/metafile.yml b/configs/ld/metafile.yml new file mode 100644 index 0000000..cd833bf --- /dev/null +++ b/configs/ld/metafile.yml @@ -0,0 +1,72 @@ +Collections: + - Name: Localization Distillation + Metadata: + Training Data: COCO + Training Techniques: + - Localization Distillation + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/2102.12252 + Title: 'Localization Distillation for Object Detection' + README: configs/ld/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.11.0/mmdet/models/dense_heads/ld_head.py#L11 + Version: v2.11.0 + +Models: + - Name: ld_r18_gflv1_r101_fpn_coco_1x + In Collection: Localization Distillation + Config: configs/ld/ld_r18_gflv1_r101_fpn_coco_1x.py + Metadata: + Teacher: R-101 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.5 + box AP@0.5: 52.9 + box AP@0.75: 39.3 + + - Name: ld_r34_gflv1_r101_fpn_coco_1x + In Collection: Localization Distillation + Config: configs/ld/ld_r34_gflv1_r101_fpn_coco_1x.py + Metadata: + Teacher: R-101 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.8 + box AP@0.5: 56.6 + box AP@0.75: 43.1 + + - Name: ld_r50_gflv1_r101_fpn_coco_1x + In Collection: Localization Distillation + Config: configs/ld/ld_r50_gflv1_r101_fpn_coco_1x.py + Metadata: + Teacher: R-101 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.1 + box AP@0.5: 58.7 + box AP@0.75: 44.9 + + - Name: ld_r101_gflv1_r101dcn_fpn_coco_1x + In Collection: Localization Distillation + Config: configs/ld/ld_r101_gflv1_r101dcn_fpn_coco_1x.py + Metadata: + Teacher: R-101-DCN + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.4 + box AP@0.5: 63.1 + box AP@0.75: 49.5 diff --git a/configs/legacy_1.x/README.md b/configs/legacy_1.x/README.md new file mode 100644 index 0000000..38a2a0e --- /dev/null +++ b/configs/legacy_1.x/README.md @@ -0,0 +1,53 @@ +# Legacy Configs in MMDetection V1.x + + + +Configs in this directory implement the legacy configs used by MMDetection V1.x and its model zoos. + +To help users convert their models from V1.x to MMDetection V2.0, we provide v1.x configs to inference the converted v1.x models. +Due to the BC-breaking changes in MMDetection V2.0 from MMDetection V1.x, running inference with the same model weights in these two version will produce different results. The difference will cause within 1% AP absolute difference as can be found in the following table. + +## Usage + +To upgrade the model version, the users need to do the following steps. + +### 1. Convert model weights + +There are three main difference in the model weights between V1.x and V2.0 codebases. + +1. Since the class order in all the detector's classification branch is reordered, all the legacy model weights need to go through the conversion process. +2. The regression and segmentation head no longer contain the background channel. Weights in these background channels should be removed to fix in the current codebase. +3. For two-stage detectors, their wegihts need to be upgraded since MMDetection V2.0 refactors all the two-stage detectors with `RoIHead`. + +The users can do the same modification as mentioned above for the self-implemented +detectors. We provide a scripts `tools/model_converters/upgrade_model_version.py` to convert the model weights in the V1.x model zoo. + +```bash +python tools/model_converters/upgrade_model_version.py ${OLD_MODEL_PATH} ${NEW_MODEL_PATH} --num-classes ${NUM_CLASSES} + +``` + +- OLD_MODEL_PATH: the path to load the model weights in 1.x version. +- NEW_MODEL_PATH: the path to save the converted model weights in 2.0 version. +- NUM_CLASSES: number of classes of the original model weights. Usually it is 81 for COCO dataset, 21 for VOC dataset. + The number of classes in V2.0 models should be equal to that in V1.x models - 1. + +### 2. Use configs with legacy settings + +After converting the model weights, checkout to the v1.2 release to find the corresponding config file that uses the legacy settings. +The V1.x models usually need these three legacy modules: `LegacyAnchorGenerator`, `LegacyDeltaXYWHBBoxCoder`, and `RoIAlign(align=False)`. +For models using ResNet Caffe backbones, they also need to change the pretrain name and the corresponding `img_norm_cfg`. +An example is in [`retinanet_r50_caffe_fpn_1x_coco_v1.py`](retinanet_r50_caffe_fpn_1x_coco_v1.py) +Then use the config to test the model weights. For most models, the obtained results should be close to that in V1.x. +We provide configs of some common structures in this directory. + +## Performance + +The performance change after converting the models in this directory are listed as the following. +| Method | Style | Lr schd | V1.x box AP | V1.x mask AP | V2.0 box AP | V2.0 mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------:| :-----: |:------:| :-----: | :-------: |:------------------------------------------------------------------------------------------------------------------------------: | +| Mask R-CNN R-50-FPN | pytorch | 1x | 37.3 | 34.2 | 36.8 | 33.9 | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/legacy_1.x/mask_rcnn_r50_fpn_1x_coco_v1.py) | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/mask_rcnn_r50_fpn_1x_20181010-069fa190.pth)| +| RetinaNet R-50-FPN | caffe | 1x | 35.8 | - | 35.4 | - | [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/legacy_1.x/retinanet_r50_caffe_1x_coco_v1.py) | +| RetinaNet R-50-FPN | pytorch | 1x | 35.6 |-|35.2| -| [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/legacy_1.x/retinanet_r50_fpn_1x_coco_v1.py) | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/retinanet_r50_fpn_1x_20181125-7b0c2548.pth) | +| Cascade Mask R-CNN R-50-FPN | pytorch | 1x | 41.2 | 35.7 |40.8| 35.6| [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/legacy_1.x/cascade_mask_rcnn_r50_fpn_1x_coco_v1.py) | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/cascade_mask_rcnn_r50_fpn_1x_20181123-88b170c9.pth) | +| SSD300-VGG16 | caffe | 120e | 25.7 |-|25.4|-| [config](https://github.com/open-mmlab/mmdetection/blob/master/configs/legacy_1.x/ssd300_coco_v1.py) | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/ssd300_coco_vgg16_caffe_120e_20181221-84d7110b.pth) | diff --git a/configs/legacy_1.x/cascade_mask_rcnn_r50_fpn_1x_coco_v1.py b/configs/legacy_1.x/cascade_mask_rcnn_r50_fpn_1x_coco_v1.py new file mode 100644 index 0000000..fc9d004 --- /dev/null +++ b/configs/legacy_1.x/cascade_mask_rcnn_r50_fpn_1x_coco_v1.py @@ -0,0 +1,79 @@ +_base_ = [ + '../_base_/models/cascade_mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='CascadeRCNN', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + anchor_generator=dict(type='LegacyAnchorGenerator', center_offset=0.5), + bbox_coder=dict( + type='LegacyDeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0])), + roi_head=dict( + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + type='RoIAlign', + output_size=7, + sampling_ratio=2, + aligned=False)), + bbox_head=[ + dict( + type='Shared2FCBBoxHead', + reg_class_agnostic=True, + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='LegacyDeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2])), + dict( + type='Shared2FCBBoxHead', + reg_class_agnostic=True, + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='LegacyDeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.05, 0.05, 0.1, 0.1])), + dict( + type='Shared2FCBBoxHead', + reg_class_agnostic=True, + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='LegacyDeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.033, 0.033, 0.067, 0.067])), + ], + mask_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + type='RoIAlign', + output_size=14, + sampling_ratio=2, + aligned=False)))) +dist_params = dict(backend='nccl', port=29515) diff --git a/configs/legacy_1.x/faster_rcnn_r50_fpn_1x_coco_v1.py b/configs/legacy_1.x/faster_rcnn_r50_fpn_1x_coco_v1.py new file mode 100644 index 0000000..8c573be --- /dev/null +++ b/configs/legacy_1.x/faster_rcnn_r50_fpn_1x_coco_v1.py @@ -0,0 +1,38 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + type='FasterRCNN', + backbone=dict( + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + rpn_head=dict( + type='RPNHead', + anchor_generator=dict( + type='LegacyAnchorGenerator', + center_offset=0.5, + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict(type='LegacyDeltaXYWHBBoxCoder'), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + type='RoIAlign', + output_size=7, + sampling_ratio=2, + aligned=False), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=dict( + bbox_coder=dict(type='LegacyDeltaXYWHBBoxCoder'), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn_proposal=dict(max_per_img=2000), + rcnn=dict(assigner=dict(match_low_quality=True)))) diff --git a/configs/legacy_1.x/mask_rcnn_r50_fpn_1x_coco_v1.py b/configs/legacy_1.x/mask_rcnn_r50_fpn_1x_coco_v1.py new file mode 100644 index 0000000..04581bb --- /dev/null +++ b/configs/legacy_1.x/mask_rcnn_r50_fpn_1x_coco_v1.py @@ -0,0 +1,34 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + rpn_head=dict( + anchor_generator=dict(type='LegacyAnchorGenerator', center_offset=0.5), + bbox_coder=dict(type='LegacyDeltaXYWHBBoxCoder'), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + type='RoIAlign', + output_size=7, + sampling_ratio=2, + aligned=False)), + mask_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict( + type='RoIAlign', + output_size=14, + sampling_ratio=2, + aligned=False)), + bbox_head=dict( + bbox_coder=dict(type='LegacyDeltaXYWHBBoxCoder'), + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + + # model training and testing settings + train_cfg=dict( + rpn_proposal=dict(max_per_img=2000), + rcnn=dict(assigner=dict(match_low_quality=True)))) diff --git a/configs/legacy_1.x/retinanet_r50_caffe_fpn_1x_coco_v1.py b/configs/legacy_1.x/retinanet_r50_caffe_fpn_1x_coco_v1.py new file mode 100644 index 0000000..a63d248 --- /dev/null +++ b/configs/legacy_1.x/retinanet_r50_caffe_fpn_1x_coco_v1.py @@ -0,0 +1,41 @@ +_base_ = './retinanet_r50_fpn_1x_coco_v1.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron/resnet50_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/legacy_1.x/retinanet_r50_fpn_1x_coco_v1.py b/configs/legacy_1.x/retinanet_r50_fpn_1x_coco_v1.py new file mode 100644 index 0000000..6198b97 --- /dev/null +++ b/configs/legacy_1.x/retinanet_r50_fpn_1x_coco_v1.py @@ -0,0 +1,17 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + bbox_head=dict( + type='RetinaHead', + anchor_generator=dict( + type='LegacyAnchorGenerator', + center_offset=0.5, + octave_base_scale=4, + scales_per_octave=3, + ratios=[0.5, 1.0, 2.0], + strides=[8, 16, 32, 64, 128]), + bbox_coder=dict(type='LegacyDeltaXYWHBBoxCoder'), + loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0))) diff --git a/configs/legacy_1.x/ssd300_coco_v1.py b/configs/legacy_1.x/ssd300_coco_v1.py new file mode 100644 index 0000000..b194e76 --- /dev/null +++ b/configs/legacy_1.x/ssd300_coco_v1.py @@ -0,0 +1,79 @@ +_base_ = [ + '../_base_/models/ssd300.py', '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_2x.py', '../_base_/default_runtime.py' +] +# model settings +input_size = 300 +model = dict( + bbox_head=dict( + type='SSDHead', + anchor_generator=dict( + type='LegacySSDAnchorGenerator', + scale_major=False, + input_size=input_size, + basesize_ratio_range=(0.15, 0.9), + strides=[8, 16, 32, 64, 100, 300], + ratios=[[2], [2, 3], [2, 3], [2, 3], [2], [2]]), + bbox_coder=dict( + type='LegacyDeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.1, 0.1, 0.2, 0.2]))) +# dataset settings +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict(mean=[123.675, 116.28, 103.53], std=[1, 1, 1], to_rgb=True) +train_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='Expand', + mean=img_norm_cfg['mean'], + to_rgb=img_norm_cfg['to_rgb'], + ratio_range=(1, 4)), + dict( + type='MinIoURandomCrop', + min_ious=(0.1, 0.3, 0.5, 0.7, 0.9), + min_crop_size=0.3), + dict(type='Resize', img_scale=(300, 300), keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(300, 300), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=8, + workers_per_gpu=3, + train=dict( + _delete_=True, + type='RepeatDataset', + times=5, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='SGD', lr=2e-3, momentum=0.9, weight_decay=5e-4) +optimizer_config = dict(_delete_=True) +dist_params = dict(backend='nccl', port=29555) diff --git a/configs/libra_rcnn/README.md b/configs/libra_rcnn/README.md new file mode 100644 index 0000000..8b78af4 --- /dev/null +++ b/configs/libra_rcnn/README.md @@ -0,0 +1,41 @@ +# Libra R-CNN: Towards Balanced Learning for Object Detection + +## Introduction + + + +We provide config files to reproduce the results in the CVPR 2019 paper [Libra R-CNN](https://arxiv.org/pdf/1904.02701.pdf). + +The extended version of [Libra R-CNN](https://arxiv.org/pdf/2108.10175.pdf) is accpeted by IJCV. + +``` +@inproceedings{pang2019libra, + title={Libra R-CNN: Towards Balanced Learning for Object Detection}, + author={Pang, Jiangmiao and Chen, Kai and Shi, Jianping and Feng, Huajun and Ouyang, Wanli and Dahua Lin}, + booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, + year={2019} +} + +@article{pang2021towards, + title={Towards Balanced Learning for Instance Recognition}, + author={Pang, Jiangmiao and Chen, Kai and Li, Qi and Xu, Zhihai and Feng, Huajun and Shi, Jianping and Ouyang, Wanli and Lin, Dahua}, + journal={International Journal of Computer Vision}, + volume={129}, + number={5}, + pages={1376--1393}, + year={2021}, + publisher={Springer} +} +``` + +## Results and models + +The results on COCO 2017val are shown in the below table. (results on test-dev are usually slightly higher than val) + +| Architecture | Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:------------:|:---------------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| Faster R-CNN | R-50-FPN | pytorch | 1x | 4.6 | 19.0 | 38.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco/libra_faster_rcnn_r50_fpn_1x_coco_20200130-3afee3a9.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco/libra_faster_rcnn_r50_fpn_1x_coco_20200130_204655.log.json) | +| Fast R-CNN | R-50-FPN | pytorch | 1x | | | | | +| Faster R-CNN | R-101-FPN | pytorch | 1x | 6.5 | 14.4 | 40.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco/libra_faster_rcnn_r101_fpn_1x_coco_20200203-8dba6a5a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco/libra_faster_rcnn_r101_fpn_1x_coco_20200203_001405.log.json) | +| Faster R-CNN | X-101-64x4d-FPN | pytorch | 1x | 10.8 | 8.5 | 42.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco/libra_faster_rcnn_x101_64x4d_fpn_1x_coco_20200315-3a7d0488.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco/libra_faster_rcnn_x101_64x4d_fpn_1x_coco_20200315_231625.log.json) | +| RetinaNet | R-50-FPN | pytorch | 1x | 4.2 | 17.7 | 37.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/libra_rcnn/libra_retinanet_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_retinanet_r50_fpn_1x_coco/libra_retinanet_r50_fpn_1x_coco_20200205-804d94ce.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_retinanet_r50_fpn_1x_coco/libra_retinanet_r50_fpn_1x_coco_20200205_112757.log.json) | diff --git a/configs/libra_rcnn/libra_fast_rcnn_r50_fpn_1x_coco.py b/configs/libra_rcnn/libra_fast_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..efbedc8 --- /dev/null +++ b/configs/libra_rcnn/libra_fast_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,50 @@ +_base_ = '../fast_rcnn/fast_rcnn_r50_fpn_1x_coco.py' +# model settings +model = dict( + neck=[ + dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + dict( + type='BFP', + in_channels=256, + num_levels=5, + refine_level=2, + refine_type='non_local') + ], + roi_head=dict( + bbox_head=dict( + loss_bbox=dict( + _delete_=True, + type='BalancedL1Loss', + alpha=0.5, + gamma=1.5, + beta=1.0, + loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rcnn=dict( + sampler=dict( + _delete_=True, + type='CombinedSampler', + num=512, + pos_fraction=0.25, + add_gt_as_proposals=True, + pos_sampler=dict(type='InstanceBalancedPosSampler'), + neg_sampler=dict( + type='IoUBalancedNegSampler', + floor_thr=-1, + floor_fraction=0, + num_bins=3))))) +# dataset settings +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +data = dict( + train=dict(proposal_file=data_root + + 'libra_proposals/rpn_r50_fpn_1x_train2017.pkl'), + val=dict(proposal_file=data_root + + 'libra_proposals/rpn_r50_fpn_1x_val2017.pkl'), + test=dict(proposal_file=data_root + + 'libra_proposals/rpn_r50_fpn_1x_val2017.pkl')) diff --git a/configs/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco.py b/configs/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..e899706 --- /dev/null +++ b/configs/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './libra_faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco.py b/configs/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..89a0d7b --- /dev/null +++ b/configs/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,41 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' +# model settings +model = dict( + neck=[ + dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + dict( + type='BFP', + in_channels=256, + num_levels=5, + refine_level=2, + refine_type='non_local') + ], + roi_head=dict( + bbox_head=dict( + loss_bbox=dict( + _delete_=True, + type='BalancedL1Loss', + alpha=0.5, + gamma=1.5, + beta=1.0, + loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict(sampler=dict(neg_pos_ub=5), allowed_border=-1), + rcnn=dict( + sampler=dict( + _delete_=True, + type='CombinedSampler', + num=512, + pos_fraction=0.25, + add_gt_as_proposals=True, + pos_sampler=dict(type='InstanceBalancedPosSampler'), + neg_sampler=dict( + type='IoUBalancedNegSampler', + floor_thr=-1, + floor_fraction=0, + num_bins=3))))) diff --git a/configs/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco.py b/configs/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..06740a7 --- /dev/null +++ b/configs/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './libra_faster_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/libra_rcnn/libra_retinanet_r50_fpn_1x_coco.py b/configs/libra_rcnn/libra_retinanet_r50_fpn_1x_coco.py new file mode 100644 index 0000000..be27420 --- /dev/null +++ b/configs/libra_rcnn/libra_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,26 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' +# model settings +model = dict( + neck=[ + dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_input', + num_outs=5), + dict( + type='BFP', + in_channels=256, + num_levels=5, + refine_level=1, + refine_type='non_local') + ], + bbox_head=dict( + loss_bbox=dict( + _delete_=True, + type='BalancedL1Loss', + alpha=0.5, + gamma=1.5, + beta=0.11, + loss_weight=1.0))) diff --git a/configs/libra_rcnn/metafile.yml b/configs/libra_rcnn/metafile.yml new file mode 100644 index 0000000..8c32795 --- /dev/null +++ b/configs/libra_rcnn/metafile.yml @@ -0,0 +1,99 @@ +Collections: + - Name: Libra R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - IoU-Balanced Sampling + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Balanced Feature Pyramid + Paper: + URL: https://arxiv.org/abs/1904.02701 + Title: 'Libra R-CNN: Towards Balanced Learning for Object Detection' + README: configs/libra_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/necks/bfp.py#L10 + Version: v2.0.0 + +Models: + - Name: libra_faster_rcnn_r50_fpn_1x_coco + In Collection: Libra R-CNN + Config: configs/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.6 + inference time (ms/im): + - value: 52.63 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_coco/libra_faster_rcnn_r50_fpn_1x_coco_20200130-3afee3a9.pth + + - Name: libra_faster_rcnn_r101_fpn_1x_coco + In Collection: Libra R-CNN + Config: configs/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.5 + inference time (ms/im): + - value: 69.44 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_coco/libra_faster_rcnn_r101_fpn_1x_coco_20200203-8dba6a5a.pth + + - Name: libra_faster_rcnn_x101_64x4d_fpn_1x_coco + In Collection: Libra R-CNN + Config: configs/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 10.8 + inference time (ms/im): + - value: 117.65 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_coco/libra_faster_rcnn_x101_64x4d_fpn_1x_coco_20200315-3a7d0488.pth + + - Name: libra_retinanet_r50_fpn_1x_coco + In Collection: Libra R-CNN + Config: configs/libra_rcnn/libra_retinanet_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.2 + inference time (ms/im): + - value: 56.5 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/libra_rcnn/libra_retinanet_r50_fpn_1x_coco/libra_retinanet_r50_fpn_1x_coco_20200205-804d94ce.pth diff --git a/configs/lvis/README.md b/configs/lvis/README.md new file mode 100644 index 0000000..f613de8 --- /dev/null +++ b/configs/lvis/README.md @@ -0,0 +1,44 @@ +# LVIS dataset + +## Introduction + + + +```latex +@inproceedings{gupta2019lvis, + title={{LVIS}: A Dataset for Large Vocabulary Instance Segmentation}, + author={Gupta, Agrim and Dollar, Piotr and Girshick, Ross}, + booktitle={Proceedings of the {IEEE} Conference on Computer Vision and Pattern Recognition}, + year={2019} +} +``` + +## Common Setting + +* Please follow [install guide](../../docs/get_started.md#install-mmdetection) to install open-mmlab forked cocoapi first. +* Run following scripts to install our forked lvis-api. + + ```shell + pip install git+https://github.com/lvis-dataset/lvis-api.git + ``` + +* All experiments use oversample strategy [here](../../docs/tutorials/customize_dataset.md#class-balanced-dataset) with oversample threshold `1e-3`. +* The size of LVIS v0.5 is half of COCO, so schedule `2x` in LVIS is roughly the same iterations as `1x` in COCO. + +## Results and models of LVIS v0.5 + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: |:--------: | +| R-50-FPN | pytorch | 2x | - | - | 26.1 | 25.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis-dbd06831.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_20200531_160435.log.json) | +| R-101-FPN | pytorch | 2x | - | - | 27.1 | 27.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis-54582ee2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis_20200601_134748.log.json) | +| X-101-32x4d-FPN | pytorch | 2x | - | - | 26.7 | 26.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis-3cf55ea2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis_20200531_221749.log.json) | +| X-101-64x4d-FPN | pytorch | 2x | - | - | 26.4 | 26.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis-1c99a5ad.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis_20200601_194651.log.json) | + +## Results and models of LVIS v1 + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| R-50-FPN | pytorch | 1x | 9.1 | - | 22.5 | 21.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1-aa78ac3d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1-20200829_061305.log.json) | +| R-101-FPN | pytorch | 1x | 10.8 | - | 24.6 | 23.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1-ec55ce32.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1-20200829_070959.log.json) | +| X-101-32x4d-FPN | pytorch | 1x | 11.8 | - | 26.7 | 25.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1-ebbc5c81.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1-20200829_071317.log.json) | +| X-101-64x4d-FPN | pytorch | 1x | 14.6 | - | 27.2 | 25.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1-43d9edfe.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1-20200830_060206.log.json) | diff --git a/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1.py b/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1.py new file mode 100644 index 0000000..0f017f5 --- /dev/null +++ b/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_1x_lvis_v1.py @@ -0,0 +1,6 @@ +_base_ = './mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py b/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py new file mode 100644 index 0000000..637f4a6 --- /dev/null +++ b/configs/lvis/mask_rcnn_r101_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py @@ -0,0 +1,6 @@ +_base_ = './mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py b/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py new file mode 100644 index 0000000..92ddb52 --- /dev/null +++ b/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py @@ -0,0 +1,31 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/lvis_v1_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + roi_head=dict( + bbox_head=dict(num_classes=1203), mask_head=dict(num_classes=1203)), + test_cfg=dict( + rcnn=dict( + score_thr=0.0001, + # LVIS allows up to 300 + max_per_img=300))) +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, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']), +] +data = dict(train=dict(dataset=dict(pipeline=train_pipeline))) diff --git a/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py b/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py new file mode 100644 index 0000000..d53c5dc --- /dev/null +++ b/configs/lvis/mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py @@ -0,0 +1,31 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/lvis_v0.5_instance.py', + '../_base_/schedules/schedule_2x.py', '../_base_/default_runtime.py' +] +model = dict( + roi_head=dict( + bbox_head=dict(num_classes=1230), mask_head=dict(num_classes=1230)), + test_cfg=dict( + rcnn=dict( + score_thr=0.0001, + # LVIS allows up to 300 + max_per_img=300))) +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, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']), +] +data = dict(train=dict(dataset=dict(pipeline=train_pipeline))) diff --git a/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py b/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py new file mode 100644 index 0000000..a6115c1 --- /dev/null +++ b/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py b/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py new file mode 100644 index 0000000..96b6252 --- /dev/null +++ b/configs/lvis/mask_rcnn_x101_32x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py b/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py new file mode 100644 index 0000000..0f95a73 --- /dev/null +++ b/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_1x_lvis_v1.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r50_fpn_sample1e-3_mstrain_1x_lvis_v1.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py b/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py new file mode 100644 index 0000000..986acda --- /dev/null +++ b/configs/lvis/mask_rcnn_x101_64x4d_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r50_fpn_sample1e-3_mstrain_2x_lvis_v0.5.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/mask_rcnn/README.md b/configs/mask_rcnn/README.md new file mode 100644 index 0000000..77cfabe --- /dev/null +++ b/configs/mask_rcnn/README.md @@ -0,0 +1,48 @@ +# Mask R-CNN + +## Introduction + + + +```latex +@article{He_2017, + title={Mask R-CNN}, + journal={2017 IEEE International Conference on Computer Vision (ICCV)}, + publisher={IEEE}, + author={He, Kaiming and Gkioxari, Georgia and Dollar, Piotr and Girshick, Ross}, + year={2017}, + month={Oct} +} +``` + +## Results and models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| R-50-FPN | caffe | 1x | 4.3 | | 38.0 | 34.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco/mask_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.38__segm_mAP-0.344_20200504_231812-0ebd1859.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco/mask_rcnn_r50_caffe_fpn_1x_coco_20200504_231812.log.json) | +| R-50-FPN | pytorch | 1x | 4.4 | 16.1 | 38.2 | 34.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205_050542.log.json) | +| R-50-FPN | pytorch | 2x | - | - | 39.2 | 35.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_2x_coco/mask_rcnn_r50_fpn_2x_coco_bbox_mAP-0.392__segm_mAP-0.354_20200505_003907-3e542a40.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_2x_coco/mask_rcnn_r50_fpn_2x_coco_20200505_003907.log.json) | +| R-101-FPN | caffe | 1x | | | 40.4 | 36.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco/mask_rcnn_r101_caffe_fpn_1x_coco_20200601_095758-805e06c1.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco/mask_rcnn_r101_caffe_fpn_1x_coco_20200601_095758.log.json)| +| R-101-FPN | pytorch | 1x | 6.4 | 13.5 | 40.0 | 36.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_1x_coco/mask_rcnn_r101_fpn_1x_coco_20200204-1efe0ed5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_1x_coco/mask_rcnn_r101_fpn_1x_coco_20200204_144809.log.json) | +| R-101-FPN | pytorch | 2x | - | - | 40.8 | 36.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_2x_coco/mask_rcnn_r101_fpn_2x_coco_bbox_mAP-0.408__segm_mAP-0.366_20200505_071027-14b391c7.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_2x_coco/mask_rcnn_r101_fpn_2x_coco_20200505_071027.log.json) | +| X-101-32x4d-FPN | pytorch | 1x | 7.6 | 11.3 | 41.9 | 37.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco/mask_rcnn_x101_32x4d_fpn_1x_coco_20200205-478d0b67.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco/mask_rcnn_x101_32x4d_fpn_1x_coco_20200205_034906.log.json) | +| X-101-32x4d-FPN | pytorch | 2x | - | - | 42.2 | 37.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco/mask_rcnn_x101_32x4d_fpn_2x_coco_bbox_mAP-0.422__segm_mAP-0.378_20200506_004702-faef898c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco/mask_rcnn_x101_32x4d_fpn_2x_coco_20200506_004702.log.json) | +| X-101-64x4d-FPN | pytorch | 1x | 10.7 | 8.0 | 42.8 | 38.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco/mask_rcnn_x101_64x4d_fpn_1x_coco_20200201-9352eb0d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco/mask_rcnn_x101_64x4d_fpn_1x_coco_20200201_124310.log.json) | +| X-101-64x4d-FPN | pytorch | 2x | - | - | 42.7 | 38.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco/mask_rcnn_x101_64x4d_fpn_2x_coco_20200509_224208-39d6f70c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco/mask_rcnn_x101_64x4d_fpn_2x_coco_20200509_224208.log.json)| +| X-101-32x8d-FPN | pytorch | 1x | - | - | 42.8 | 38.3 | | + +## Pre-trained Models + +We also train some models with longer schedules and multi-scale training. The users could finetune them for downstream tasks. + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| [R-50-FPN](./mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py) | caffe | 2x | 4.3 | | 40.3 | 36.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco_bbox_mAP-0.403__segm_mAP-0.365_20200504_231822-a75c98ce.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco_20200504_231822.log.json) +| [R-50-FPN](./mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py) | caffe | 3x | 4.3 | | 40.8 | 37.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_20200504_163245.log.json) +| [R-50-FPN](./mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py) | pytorch| 3x | 4.1 | | 40.9 | 37.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_fpn_mstrain-poly_3x_coco_20210524_201154-21b550bb.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_fpn_mstrain-poly_3x_coco_20210524_201154.log.json) +| [R-101-FPN](./mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py) | caffe | 3x | 5.9 | | 42.9 | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco_20210526_132339-3c33ce02.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco_20210526_132339.log.json) +| [R-101-FPN](./mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py) | pytorch| 3x | 6.1 | | 42.7 | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco/mask_rcnn_r101_fpn_mstrain-poly_3x_coco_20210524_200244-5675c317.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco/mask_rcnn_r101_fpn_mstrain-poly_3x_coco_20210524_200244.log.json) +| [x101-32x4d-FPN](./mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py) | pytorch| 3x | 7.3 | | 43.6 | 39.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco_20210524_201410-abcd7859.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco_20210524_201410.log.json) +| [X-101-32x8d-FPN](./mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py) | pytorch | 1x | - | | 43.6 | 39.0 | +| [X-101-32x8d-FPN](./mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py) | pytorch | 3x | 10.3 | | 44.3 | 39.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco_20210607_161042-8bd2c639.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco_20210607_161042.log.json) +| [X-101-64x4d-FPN](./mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py) | pytorch | 3x | 10.4 | | 44.5 | 39.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco_20210526_120447-c376f129.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco_20210526_120447.log.json) diff --git a/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..95b324f --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './mask_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..e39781d --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,55 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + depth=101, + norm_cfg=dict(requires_grad=False), + norm_eval=True, + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', + with_bbox=True, + with_mask=True, + poly2mask=False), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..b7986e8 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py b/configs/mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py new file mode 100644 index 0000000..c9059d5 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py @@ -0,0 +1,6 @@ +_base_ = './mask_rcnn_r50_fpn_2x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..0696cbe --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,10 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_c4_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_c4_1x_coco.py new file mode 100644 index 0000000..a44c018 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_c4_1x_coco.py @@ -0,0 +1,39 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_caffe_c4.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..5a23f8c --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,40 @@ +_base_ = './mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py new file mode 100644 index 0000000..6308e40 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py @@ -0,0 +1,49 @@ +_base_ = './mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', + with_bbox=True, + with_mask=True, + poly2mask=False), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py new file mode 100644 index 0000000..4f7150c --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 23]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..1b48a21 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,4 @@ +_base_ = './mask_rcnn_r50_caffe_fpn_mstrain-poly_1x_coco.py' +# learning policy +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain_1x_coco.py new file mode 100644 index 0000000..bebbaaa --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain_1x_coco.py @@ -0,0 +1,45 @@ +_base_ = './mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe'))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_poly_1x_coco_v1.py b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_poly_1x_coco_v1.py new file mode 100644 index 0000000..3f8079d --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_poly_1x_coco_v1.py @@ -0,0 +1,61 @@ +_base_ = './mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + norm_cfg=dict(requires_grad=False), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + rpn_head=dict( + loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)), + roi_head=dict( + bbox_roi_extractor=dict( + roi_layer=dict( + type='RoIAlign', + output_size=7, + sampling_ratio=2, + aligned=False)), + bbox_head=dict( + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), + mask_roi_extractor=dict( + roi_layer=dict( + type='RoIAlign', + output_size=14, + sampling_ratio=2, + aligned=False)))) +# use caffe img_norm +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', + with_bbox=True, + with_mask=True, + poly2mask=False), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..6a6c924 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] diff --git a/configs/mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py new file mode 100644 index 0000000..932b1f9 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py @@ -0,0 +1,5 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_2x.py', '../_base_/default_runtime.py' +] diff --git a/configs/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..b3d9242 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,4 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] diff --git a/configs/mask_rcnn/mask_rcnn_r50_fpn_poly_1x_coco.py b/configs/mask_rcnn/mask_rcnn_r50_fpn_poly_1x_coco.py new file mode 100644 index 0000000..9eb6d57 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_r50_fpn_poly_1x_coco.py @@ -0,0 +1,23 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +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, + with_mask=True, + poly2mask=False), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +data = dict(train=dict(pipeline=train_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..a8b3799 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco.py new file mode 100644 index 0000000..2cd3cee --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_r101_fpn_2x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..b698a7d --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,18 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_1x_coco.py new file mode 100644 index 0000000..108ea4e --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_1x_coco.py @@ -0,0 +1,65 @@ +_base_ = './mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=8, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + style='pytorch', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnext101_32x8d'))) + +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], + std=[57.375, 57.120, 58.395], + to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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=2, + workers_per_gpu=2, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_1x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_1x_coco.py new file mode 100644 index 0000000..6b912f6 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_1x_coco.py @@ -0,0 +1,60 @@ +_base_ = './mask_rcnn_r101_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=8, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + style='pytorch', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnext101_32x8d'))) + +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], + std=[57.375, 57.120, 58.395], + to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', + with_bbox=True, + with_mask=True, + poly2mask=False), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..8ba0e9c --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,85 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=8, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + style='pytorch', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnext101_32x8d'))) + +dataset_type = 'CocoDataset' +data_root = 'data/coco/' +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], + std=[57.375, 57.120, 58.395], + to_rgb=False) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadAnnotations', + with_bbox=True, + with_mask=True, + poly2mask=False), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + samples_per_gpu=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline)), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline)) diff --git a/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..2333b03 --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_x101_32x4d_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco.py new file mode 100644 index 0000000..6074cca --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco.py @@ -0,0 +1,14 @@ +_base_ = './mask_rcnn_x101_32x4d_fpn_2x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py b/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..9f9cb1c --- /dev/null +++ b/configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,18 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/mask_rcnn/metafile.yml b/configs/mask_rcnn/metafile.yml new file mode 100644 index 0000000..747a99a --- /dev/null +++ b/configs/mask_rcnn/metafile.yml @@ -0,0 +1,419 @@ +Collections: + - Name: Mask R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Softmax + - RPN + - Convolution + - Dense Connections + - FPN + - ResNet + - RoIAlign + Paper: + URL: https://arxiv.org/abs/1703.06870v3 + Title: 'Mask R-CNN' + README: configs/mask_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/mask_rcnn.py#L6 + Version: v2.0.0 + +Models: + - Name: mask_rcnn_r50_caffe_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.3 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 34.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco/mask_rcnn_r50_caffe_fpn_1x_coco_bbox_mAP-0.38__segm_mAP-0.344_20200504_231812-0ebd1859.pth + + - Name: mask_rcnn_r50_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.4 + inference time (ms/im): + - value: 62.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 34.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth + + - Name: mask_rcnn_r50_fpn_2x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r50_fpn_2x_coco.py + Metadata: + Training Memory (GB): 4.4 + inference time (ms/im): + - value: 62.11 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 35.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_2x_coco/mask_rcnn_r50_fpn_2x_coco_bbox_mAP-0.392__segm_mAP-0.354_20200505_003907-3e542a40.pth + + - Name: mask_rcnn_r101_caffe_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_caffe_fpn_1x_coco/mask_rcnn_r101_caffe_fpn_1x_coco_20200601_095758-805e06c1.pth + + - Name: mask_rcnn_r101_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.4 + inference time (ms/im): + - value: 74.07 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_1x_coco/mask_rcnn_r101_fpn_1x_coco_20200204-1efe0ed5.pth + + - Name: mask_rcnn_r101_fpn_2x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r101_fpn_2x_coco.py + Metadata: + Training Memory (GB): 6.4 + inference time (ms/im): + - value: 74.07 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_2x_coco/mask_rcnn_r101_fpn_2x_coco_bbox_mAP-0.408__segm_mAP-0.366_20200505_071027-14b391c7.pth + + - Name: mask_rcnn_x101_32x4d_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.6 + inference time (ms/im): + - value: 88.5 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco/mask_rcnn_x101_32x4d_fpn_1x_coco_20200205-478d0b67.pth + + - Name: mask_rcnn_x101_32x4d_fpn_2x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco.py + Metadata: + Training Memory (GB): 7.6 + inference time (ms/im): + - value: 88.5 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_2x_coco/mask_rcnn_x101_32x4d_fpn_2x_coco_bbox_mAP-0.422__segm_mAP-0.378_20200506_004702-faef898c.pth + + - Name: mask_rcnn_x101_64x4d_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 10.7 + inference time (ms/im): + - value: 125 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_1x_coco/mask_rcnn_x101_64x4d_fpn_1x_coco_20200201-9352eb0d.pth + + - Name: mask_rcnn_x101_64x4d_fpn_2x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco.py + Metadata: + Training Memory (GB): 10.7 + inference time (ms/im): + - value: 125 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_2x_coco/mask_rcnn_x101_64x4d_fpn_2x_coco_20200509_224208-39d6f70c.pth + + - Name: mask_rcnn_x101_32x8d_fpn_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 10.7 + inference time (ms/im): + - value: 125 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.3 + + - Name: mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco.py + Metadata: + Training Memory (GB): 4.3 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_2x_coco_bbox_mAP-0.403__segm_mAP-0.365_20200504_231822-a75c98ce.pth + + - Name: mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 4.3 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth + + - Name: mask_rcnn_r50_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 4.1 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_fpn_mstrain-poly_3x_coco_20210524_201154-21b550bb.pth + + - Name: mask_rcnn_r101_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 6.1 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_mstrain-poly_3x_coco/mask_rcnn_r101_fpn_mstrain-poly_3x_coco_20210524_200244-5675c317.pth + + - Name: mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 5.9 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r101_caffe_fpn_mstrain-poly_3x_coco_20210526_132339-3c33ce02.pth + + - Name: mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 7.3 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_32x4d_fpn_mstrain-poly_3x_coco_20210524_201410-abcd7859.pth + + - Name: mask_rcnn_x101_32x8d_fpn_mstrain-poly_1x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.0 + + - Name: mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco + Metadata: + Training Memory (GB): 10.3 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_32x8d_fpn_mstrain-poly_3x_coco_20210607_161042-8bd2c639.pth + + - Name: mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco + In Collection: Mask R-CNN + Config: configs/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco.py + Metadata: + Epochs: 36 + Training Memory (GB): 10.4 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco/mask_rcnn_x101_64x4d_fpn_mstrain-poly_3x_coco_20210526_120447-c376f129.pth diff --git a/configs/ms_rcnn/README.md b/configs/ms_rcnn/README.md new file mode 100644 index 0000000..f36b64c --- /dev/null +++ b/configs/ms_rcnn/README.md @@ -0,0 +1,26 @@ +# Mask Scoring R-CNN + +## Introduction + + + +``` +@inproceedings{huang2019msrcnn, + title={Mask Scoring R-CNN}, + author={Zhaojin Huang and Lichao Huang and Yongchao Gong and Chang Huang and Xinggang Wang}, + booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, + year={2019}, +} +``` + +## Results and Models + +| Backbone | style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:-------------:|:----------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN | caffe | 1x | 4.5 | | 38.2 | 36.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco/ms_rcnn_r50_caffe_fpn_1x_coco_20200702_180848-61c9355e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco/ms_rcnn_r50_caffe_fpn_1x_coco_20200702_180848.log.json) | +| R-50-FPN | caffe | 2x | - | - | 38.8 | 36.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco/ms_rcnn_r50_caffe_fpn_2x_coco_bbox_mAP-0.388__segm_mAP-0.363_20200506_004738-ee87b137.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco/ms_rcnn_r50_caffe_fpn_2x_coco_20200506_004738.log.json) | +| R-101-FPN | caffe | 1x | 6.5 | | 40.4 | 37.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco/ms_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.404__segm_mAP-0.376_20200506_004755-b9b12a37.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco/ms_rcnn_r101_caffe_fpn_1x_coco_20200506_004755.log.json) | +| R-101-FPN | caffe | 2x | - | - | 41.1 | 38.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco/ms_rcnn_r101_caffe_fpn_2x_coco_bbox_mAP-0.411__segm_mAP-0.381_20200506_011134-5f3cc74f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco/ms_rcnn_r101_caffe_fpn_2x_coco_20200506_011134.log.json) | +| R-X101-32x4d | pytorch | 2x | 7.9 | 11.0 | 41.8 | 38.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco/ms_rcnn_x101_32x4d_fpn_1x_coco_20200206-81fd1740.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco/ms_rcnn_x101_32x4d_fpn_1x_coco_20200206_100113.log.json) | +| R-X101-64x4d | pytorch | 1x | 11.0 | 8.0 | 43.0 | 39.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco/ms_rcnn_x101_64x4d_fpn_1x_coco_20200206-86ba88d2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco/ms_rcnn_x101_64x4d_fpn_1x_coco_20200206_091744.log.json) | +| R-X101-64x4d | pytorch | 2x | 11.0 | 8.0 | 42.6 | 39.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco/ms_rcnn_x101_64x4d_fpn_2x_coco_20200308-02a445e2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco/ms_rcnn_x101_64x4d_fpn_2x_coco_20200308_012247.log.json) | diff --git a/configs/ms_rcnn/metafile.yml b/configs/ms_rcnn/metafile.yml new file mode 100644 index 0000000..a6c7dc5 --- /dev/null +++ b/configs/ms_rcnn/metafile.yml @@ -0,0 +1,159 @@ +Collections: + - Name: Mask Scoring R-CNN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - RPN + - FPN + - ResNet + - RoIAlign + Paper: + URL: https://arxiv.org/abs/1903.00241 + Title: 'Mask Scoring R-CNN' + README: configs/ms_rcnn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/mask_scoring_rcnn.py#L6 + Version: v2.0.0 + +Models: + - Name: ms_rcnn_r50_caffe_fpn_1x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco/ms_rcnn_r50_caffe_fpn_1x_coco_20200702_180848-61c9355e.pth + + - Name: ms_rcnn_r50_caffe_fpn_2x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py + Metadata: + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco/ms_rcnn_r50_caffe_fpn_2x_coco_bbox_mAP-0.388__segm_mAP-0.363_20200506_004738-ee87b137.pth + + - Name: ms_rcnn_r101_caffe_fpn_1x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco/ms_rcnn_r101_caffe_fpn_1x_coco_bbox_mAP-0.404__segm_mAP-0.376_20200506_004755-b9b12a37.pth + + - Name: ms_rcnn_r101_caffe_fpn_2x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py + Metadata: + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco/ms_rcnn_r101_caffe_fpn_2x_coco_bbox_mAP-0.411__segm_mAP-0.381_20200506_011134-5f3cc74f.pth + + - Name: ms_rcnn_x101_32x4d_fpn_1x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.9 + inference time (ms/im): + - value: 90.91 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco/ms_rcnn_x101_32x4d_fpn_1x_coco_20200206-81fd1740.pth + + - Name: ms_rcnn_x101_64x4d_fpn_1x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py + Metadata: + Training Memory (GB): 11.0 + inference time (ms/im): + - value: 125 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco/ms_rcnn_x101_64x4d_fpn_1x_coco_20200206-86ba88d2.pth + + - Name: ms_rcnn_x101_64x4d_fpn_2x_coco + In Collection: Mask Scoring R-CNN + Config: configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py + Metadata: + Training Memory (GB): 11.0 + inference time (ms/im): + - value: 125 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco/ms_rcnn_x101_64x4d_fpn_2x_coco_20200308-02a445e2.pth diff --git a/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py b/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..9b7dcbb --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = './ms_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet101_caffe'))) diff --git a/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py b/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py new file mode 100644 index 0000000..202bcce --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_r101_caffe_fpn_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './ms_rcnn_r101_caffe_fpn_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py b/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py new file mode 100644 index 0000000..5845125 --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_caffe_fpn_1x_coco.py' +model = dict( + type='MaskScoringRCNN', + roi_head=dict( + type='MaskScoringRoIHead', + mask_iou_head=dict( + type='MaskIoUHead', + num_convs=4, + num_fcs=2, + roi_feat_size=14, + in_channels=256, + conv_out_channels=256, + fc_out_channels=1024, + num_classes=80)), + # model training and testing settings + train_cfg=dict(rcnn=dict(mask_thr_binary=0.5))) diff --git a/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py b/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py new file mode 100644 index 0000000..008a70a --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_r50_caffe_fpn_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './ms_rcnn_r50_caffe_fpn_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/ms_rcnn/ms_rcnn_r50_fpn_1x_coco.py b/configs/ms_rcnn/ms_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..0a163ce --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' +model = dict( + type='MaskScoringRCNN', + roi_head=dict( + type='MaskScoringRoIHead', + mask_iou_head=dict( + type='MaskIoUHead', + num_convs=4, + num_fcs=2, + roi_feat_size=14, + in_channels=256, + conv_out_channels=256, + fc_out_channels=1024, + num_classes=80)), + # model training and testing settings + train_cfg=dict(rcnn=dict(mask_thr_binary=0.5))) diff --git a/configs/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..20479bb --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ms_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=32, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_32x4d'))) diff --git a/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py b/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py new file mode 100644 index 0000000..ee5b734 --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = './ms_rcnn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='ResNeXt', + depth=101, + groups=64, + base_width=4, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://resnext101_64x4d'))) diff --git a/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py b/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py new file mode 100644 index 0000000..54c605b --- /dev/null +++ b/configs/ms_rcnn/ms_rcnn_x101_64x4d_fpn_2x_coco.py @@ -0,0 +1,4 @@ +_base_ = './ms_rcnn_x101_64x4d_fpn_1x_coco.py' +# learning policy +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/nas_fcos/README.md b/configs/nas_fcos/README.md new file mode 100644 index 0000000..21a2b22 --- /dev/null +++ b/configs/nas_fcos/README.md @@ -0,0 +1,25 @@ +# NAS-FCOS: Fast Neural Architecture Search for Object Detection + +## Introduction + + + +```latex +@article{wang2019fcos, + title={Nas-fcos: Fast neural architecture search for object detection}, + author={Wang, Ning and Gao, Yang and Chen, Hao and Wang, Peng and Tian, Zhi and Shen, Chunhua}, + journal={arXiv preprint arXiv:1906.04423}, + year={2019} +} +``` + +## Results and Models + +| Head | Backbone | Style | GN-head | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:---------:|:-------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| NAS-FCOSHead | R-50 | caffe | Y | 1x | | | 39.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco_20200520-1bdba3ce.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco_20200520.log.json) | +| FCOSHead | R-50 | caffe | Y | 1x | | | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco_20200521-7fdcbce0.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco_20200521.log.json) | + +**Notes:** + +- To be consistent with the author's implementation, we use 4 GPUs with 4 images/GPU. diff --git a/configs/nas_fcos/metafile.yml b/configs/nas_fcos/metafile.yml new file mode 100644 index 0000000..1ea28cf --- /dev/null +++ b/configs/nas_fcos/metafile.yml @@ -0,0 +1,44 @@ +Collections: + - Name: NAS-FCOS + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 4x V100 GPUs + Architecture: + - FPN + - NAS-FCOS + - ResNet + Paper: + URL: https://arxiv.org/abs/1906.04423 + Title: 'NAS-FCOS: Fast Neural Architecture Search for Object Detection' + README: configs/nas_fcos/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.1.0/mmdet/models/detectors/nasfcos.py#L6 + Version: v2.1.0 + +Models: + - Name: nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco + In Collection: NAS-FCOS + Config: configs/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco_20200520-1bdba3ce.pth + + - Name: nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco + In Collection: NAS-FCOS + Config: configs/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco_20200521-7fdcbce0.pth diff --git a/configs/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco.py b/configs/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco.py new file mode 100644 index 0000000..a455c92 --- /dev/null +++ b/configs/nas_fcos/nas_fcos_fcoshead_r50_caffe_fpn_gn-head_4x4_1x_coco.py @@ -0,0 +1,100 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + type='NASFCOS', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False, eps=0), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + neck=dict( + type='NASFCOS_FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs=True, + num_outs=5, + norm_cfg=dict(type='BN'), + conv_cfg=dict(type='DCNv2', deform_groups=2)), + bbox_head=dict( + type='FCOSHead', + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + strides=[8, 16, 32, 64, 128], + norm_cfg=dict(type='GN', num_groups=32), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='IoULoss', loss_weight=1.0), + loss_centerness=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), + train_cfg=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) + +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) + +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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=4, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) + +optimizer = dict( + lr=0.01, paramwise_cfg=dict(bias_lr_mult=2., bias_decay_mult=0.)) diff --git a/configs/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco.py b/configs/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco.py new file mode 100644 index 0000000..b779492 --- /dev/null +++ b/configs/nas_fcos/nas_fcos_nashead_r50_caffe_fpn_gn-head_4x4_1x_coco.py @@ -0,0 +1,99 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] + +model = dict( + type='NASFCOS', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False, eps=0), + style='caffe', + init_cfg=dict( + type='Pretrained', + checkpoint='open-mmlab://detectron2/resnet50_caffe')), + neck=dict( + type='NASFCOS_FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs=True, + num_outs=5, + norm_cfg=dict(type='BN'), + conv_cfg=dict(type='DCNv2', deform_groups=2)), + bbox_head=dict( + type='NASFCOSHead', + num_classes=80, + in_channels=256, + feat_channels=256, + strides=[8, 16, 32, 64, 128], + norm_cfg=dict(type='GN', num_groups=32), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='IoULoss', loss_weight=1.0), + loss_centerness=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)), + train_cfg=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) + +img_norm_cfg = dict( + mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False) + +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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=4, + workers_per_gpu=2, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) + +optimizer = dict( + lr=0.01, paramwise_cfg=dict(bias_lr_mult=2., bias_decay_mult=0.)) diff --git a/configs/nas_fpn/README.md b/configs/nas_fpn/README.md new file mode 100644 index 0000000..9862b9a --- /dev/null +++ b/configs/nas_fpn/README.md @@ -0,0 +1,26 @@ +# NAS-FPN: Learning Scalable Feature Pyramid Architecture for Object Detection + +## Introduction + + + +```latex +@inproceedings{ghiasi2019fpn, + title={Nas-fpn: Learning scalable feature pyramid architecture for object detection}, + author={Ghiasi, Golnaz and Lin, Tsung-Yi and Le, Quoc V}, + booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition}, + pages={7036--7045}, + year={2019} +} +``` + +## Results and Models + +We benchmark the new training schedule (crop training, large batch, unfrozen BN, 50 epochs) introduced in NAS-FPN. RetinaNet is used in the paper. + +| Backbone | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:-----------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| R-50-FPN | 50e | 12.9 | 22.9 | 37.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/nas_fpn/retinanet_r50_fpn_crop640_50e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/nas_fpn/retinanet_r50_fpn_crop640_50e_coco/retinanet_r50_fpn_crop640_50e_coco-9b953d76.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/nas_fpn/retinanet_r50_fpn_crop640_50e_coco/retinanet_r50_fpn_crop640_50e_coco_20200529_095329.log.json) | +| R-50-NASFPN | 50e | 13.2 | 23.0 | 40.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco/retinanet_r50_nasfpn_crop640_50e_coco-0ad1f644.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco/retinanet_r50_nasfpn_crop640_50e_coco_20200528_230008.log.json) | + +**Note**: We find that it is unstable to train NAS-FPN and there is a small chance that results can be 3% mAP lower. diff --git a/configs/nas_fpn/metafile.yml b/configs/nas_fpn/metafile.yml new file mode 100644 index 0000000..ab8d649 --- /dev/null +++ b/configs/nas_fpn/metafile.yml @@ -0,0 +1,59 @@ +Collections: + - Name: NAS-FPN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - NAS-FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/1904.07392 + Title: 'NAS-FPN: Learning Scalable Feature Pyramid Architecture for Object Detection' + README: configs/nas_fpn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/necks/nas_fpn.py#L67 + Version: v2.0.0 + +Models: + - Name: retinanet_r50_fpn_crop640_50e_coco + In Collection: NAS-FPN + Config: configs/nas_fpn/retinanet_r50_fpn_crop640_50e_coco.py + Metadata: + Training Memory (GB): 12.9 + inference time (ms/im): + - value: 43.67 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/nas_fpn/retinanet_r50_fpn_crop640_50e_coco/retinanet_r50_fpn_crop640_50e_coco-9b953d76.pth + + - Name: retinanet_r50_nasfpn_crop640_50e_coco + In Collection: NAS-FPN + Config: configs/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py + Metadata: + Training Memory (GB): 13.2 + inference time (ms/im): + - value: 43.48 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 50 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco/retinanet_r50_nasfpn_crop640_50e_coco-0ad1f644.pth diff --git a/configs/nas_fpn/retinanet_r50_fpn_crop640_50e_coco.py b/configs/nas_fpn/retinanet_r50_fpn_crop640_50e_coco.py new file mode 100644 index 0000000..6ea44a0 --- /dev/null +++ b/configs/nas_fpn/retinanet_r50_fpn_crop640_50e_coco.py @@ -0,0 +1,80 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', + '../_base_/datasets/coco_detection.py', '../_base_/default_runtime.py' +] +cudnn_benchmark = True +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=norm_cfg, + norm_eval=False, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + relu_before_extra_convs=True, + no_norm_on_lateral=True, + norm_cfg=norm_cfg), + bbox_head=dict(type='RetinaSepBNHead', num_ins=5, norm_cfg=norm_cfg), + # training and testing settings + train_cfg=dict(assigner=dict(neg_iou_thr=0.5))) +# dataset settings +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=(640, 640), + ratio_range=(0.8, 1.2), + keep_ratio=True), + dict(type='RandomCrop', crop_size=(640, 640)), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size=(640, 640)), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(640, 640), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=64), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=8, + workers_per_gpu=4, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', + lr=0.08, + momentum=0.9, + weight_decay=0.0001, + paramwise_cfg=dict(norm_decay_mult=0, bypass_duplicate=True)) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=1000, + warmup_ratio=0.1, + step=[30, 40]) +# runtime settings +runner = dict(type='EpochBasedRunner', max_epochs=50) diff --git a/configs/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py b/configs/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py new file mode 100644 index 0000000..3e03919 --- /dev/null +++ b/configs/nas_fpn/retinanet_r50_nasfpn_crop640_50e_coco.py @@ -0,0 +1,79 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', + '../_base_/datasets/coco_detection.py', '../_base_/default_runtime.py' +] +cudnn_benchmark = True +# model settings +norm_cfg = dict(type='BN', requires_grad=True) +model = dict( + type='RetinaNet', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=norm_cfg, + norm_eval=False, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict(type='NASFPN', stack_times=7, norm_cfg=norm_cfg), + bbox_head=dict(type='RetinaSepBNHead', num_ins=5, norm_cfg=norm_cfg), + # training and testing settings + train_cfg=dict(assigner=dict(neg_iou_thr=0.5))) +# dataset settings +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=(640, 640), + ratio_range=(0.8, 1.2), + keep_ratio=True), + dict(type='RandomCrop', crop_size=(640, 640)), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size=(640, 640)), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(640, 640), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=128), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=8, + workers_per_gpu=4, + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', + lr=0.08, + momentum=0.9, + weight_decay=0.0001, + paramwise_cfg=dict(norm_decay_mult=0, bypass_duplicate=True)) +optimizer_config = dict(grad_clip=None) +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=1000, + warmup_ratio=0.1, + step=[30, 40]) +# runtime settings +runner = dict(type='EpochBasedRunner', max_epochs=50) diff --git a/configs/paa/README.md b/configs/paa/README.md new file mode 100644 index 0000000..3e9b6e3 --- /dev/null +++ b/configs/paa/README.md @@ -0,0 +1,35 @@ +# Probabilistic Anchor Assignment with IoU Prediction for Object Detection + + + +```latex +@inproceedings{paa-eccv2020, + title={Probabilistic Anchor Assignment with IoU Prediction for Object Detection}, + author={Kim, Kang and Lee, Hee Seok}, + booktitle = {ECCV}, + year={2020} +} +``` + +## Results and Models + +We provide config files to reproduce the object detection results in the +ECCV 2020 paper for Probabilistic Anchor Assignment with IoU +Prediction for Object Detection. + +| Backbone | Lr schd | Mem (GB) | Score voting | box AP | Config | Download | +|:-----------:|:-------:|:--------:|:------------:|:------:|:------:|:--------:| +| R-50-FPN | 12e | 3.7 | True | 40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_1x_coco/paa_r50_fpn_1x_coco_20200821-936edec3.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_1x_coco/paa_r50_fpn_1x_coco_20200821-936edec3.log.json) | +| R-50-FPN | 12e | 3.7 | False | 40.2 | - | +| R-50-FPN | 18e | 3.7 | True | 41.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r50_fpn_1.5x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_1.5x_coco/paa_r50_fpn_1.5x_coco_20200823-805d6078.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_1.5x_coco/paa_r50_fpn_1.5x_coco_20200823-805d6078.log.json) | +| R-50-FPN | 18e | 3.7 | False | 41.2 | - | +| R-50-FPN | 24e | 3.7 | True | 41.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r50_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_2x_coco/paa_r50_fpn_2x_coco_20200821-c98bfc4e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_2x_coco/paa_r50_fpn_2x_coco_20200821-c98bfc4e.log.json) | +| R-50-FPN | 36e | 3.7 | True | 43.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r50_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_mstrain_3x_coco/paa_r50_fpn_mstrain_3x_coco_20210121_145722-06a6880b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_mstrain_3x_coco/paa_r50_fpn_mstrain_3x_coco_20210121_145722.log.json) | +| R-101-FPN | 12e | 6.2 | True | 42.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_1x_coco/paa_r101_fpn_1x_coco_20200821-0a1825a4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_1x_coco/paa_r101_fpn_1x_coco_20200821-0a1825a4.log.json) | +| R-101-FPN | 12e | 6.2 | False | 42.4 | - | +| R-101-FPN | 24e | 6.2 | True | 43.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r101_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_2x_coco/paa_r101_fpn_2x_coco_20200821-6829f96b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_2x_coco/paa_r101_fpn_2x_coco_20200821-6829f96b.log.json) | +| R-101-FPN | 36e | 6.2 | True | 45.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/paa/paa_r101_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_mstrain_3x_coco/paa_r101_fpn_mstrain_3x_coco_20210122_084202-83250d22.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_mstrain_3x_coco/paa_r101_fpn_mstrain_3x_coco_20210122_084202.log.json) | + +**Note**: + +1. We find that the performance is unstable with 1x setting and may fluctuate by about 0.2 mAP. We report the best results. diff --git a/configs/paa/metafile.yml b/configs/paa/metafile.yml new file mode 100644 index 0000000..e08b663 --- /dev/null +++ b/configs/paa/metafile.yml @@ -0,0 +1,104 @@ +Collections: + - Name: PAA + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - Probabilistic Anchor Assignment + - ResNet + Paper: + URL: https://arxiv.org/abs/2007.08103 + Title: 'Probabilistic Anchor Assignment with IoU Prediction for Object Detection' + README: configs/paa/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.4.0/mmdet/models/detectors/paa.py#L6 + Version: v2.4.0 + +Models: + - Name: paa_r50_fpn_1x_coco + In Collection: PAA + Config: configs/paa/paa_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.7 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_1x_coco/paa_r50_fpn_1x_coco_20200821-936edec3.pth + + - Name: paa_r50_fpn_1.5x_coco + In Collection: PAA + Config: configs/paa/paa_r50_fpn_1.5x_coco.py + Metadata: + Training Memory (GB): 3.7 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_1.5x_coco/paa_r50_fpn_1.5x_coco_20200823-805d6078.pth + + - Name: paa_r50_fpn_2x_coco + In Collection: PAA + Config: configs/paa/paa_r50_fpn_2x_coco.py + Metadata: + Training Memory (GB): 3.7 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_2x_coco/paa_r50_fpn_2x_coco_20200821-c98bfc4e.pth + + - Name: paa_r50_fpn_mstrain_3x_coco + In Collection: PAA + Config: configs/paa/paa_r50_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 3.7 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r50_fpn_mstrain_3x_coco/paa_r50_fpn_mstrain_3x_coco_20210121_145722-06a6880b.pth + + - Name: paa_r101_fpn_1x_coco + In Collection: PAA + Config: configs/paa/paa_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.2 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_1x_coco/paa_r101_fpn_1x_coco_20200821-0a1825a4.pth + + - Name: paa_r101_fpn_2x_coco + In Collection: PAA + Config: configs/paa/paa_r101_fpn_2x_coco.py + Metadata: + Training Memory (GB): 6.2 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_2x_coco/paa_r101_fpn_2x_coco_20200821-6829f96b.pth + + - Name: paa_r101_fpn_mstrain_3x_coco + In Collection: PAA + Config: configs/paa/paa_r101_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 6.2 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/paa/paa_r101_fpn_mstrain_3x_coco/paa_r101_fpn_mstrain_3x_coco_20210122_084202-83250d22.pth diff --git a/configs/paa/paa_r101_fpn_1x_coco.py b/configs/paa/paa_r101_fpn_1x_coco.py new file mode 100644 index 0000000..94f1c27 --- /dev/null +++ b/configs/paa/paa_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './paa_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/paa/paa_r101_fpn_2x_coco.py b/configs/paa/paa_r101_fpn_2x_coco.py new file mode 100644 index 0000000..641ef76 --- /dev/null +++ b/configs/paa/paa_r101_fpn_2x_coco.py @@ -0,0 +1,3 @@ +_base_ = './paa_r101_fpn_1x_coco.py' +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/paa/paa_r101_fpn_mstrain_3x_coco.py b/configs/paa/paa_r101_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..71858ed --- /dev/null +++ b/configs/paa/paa_r101_fpn_mstrain_3x_coco.py @@ -0,0 +1,6 @@ +_base_ = './paa_r50_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/paa/paa_r50_fpn_1.5x_coco.py b/configs/paa/paa_r50_fpn_1.5x_coco.py new file mode 100644 index 0000000..aabce4a --- /dev/null +++ b/configs/paa/paa_r50_fpn_1.5x_coco.py @@ -0,0 +1,3 @@ +_base_ = './paa_r50_fpn_1x_coco.py' +lr_config = dict(step=[12, 16]) +runner = dict(type='EpochBasedRunner', max_epochs=18) diff --git a/configs/paa/paa_r50_fpn_1x_coco.py b/configs/paa/paa_r50_fpn_1x_coco.py new file mode 100644 index 0000000..4c9c4aa --- /dev/null +++ b/configs/paa/paa_r50_fpn_1x_coco.py @@ -0,0 +1,70 @@ +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='PAA', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs='on_output', + num_outs=5), + bbox_head=dict( + type='PAAHead', + reg_decoded_bbox=True, + score_voting=True, + topk=9, + num_classes=80, + in_channels=256, + stacked_convs=4, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + ratios=[1.0], + octave_base_scale=8, + scales_per_octave=1, + strides=[8, 16, 32, 64, 128]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[0.1, 0.1, 0.2, 0.2]), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='GIoULoss', loss_weight=1.3), + loss_centerness=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=0.5)), + # training and testing settings + train_cfg=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.1, + neg_iou_thr=0.1, + min_pos_iou=0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + debug=False), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) diff --git a/configs/paa/paa_r50_fpn_2x_coco.py b/configs/paa/paa_r50_fpn_2x_coco.py new file mode 100644 index 0000000..663d2c0 --- /dev/null +++ b/configs/paa/paa_r50_fpn_2x_coco.py @@ -0,0 +1,3 @@ +_base_ = './paa_r50_fpn_1x_coco.py' +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/paa/paa_r50_fpn_mstrain_3x_coco.py b/configs/paa/paa_r50_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..91fa28c --- /dev/null +++ b/configs/paa/paa_r50_fpn_mstrain_3x_coco.py @@ -0,0 +1,20 @@ +_base_ = './paa_r50_fpn_1x_coco.py' +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=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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']), +] +data = dict(train=dict(pipeline=train_pipeline)) +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/pafpn/README.md b/configs/pafpn/README.md new file mode 100644 index 0000000..9602c6d --- /dev/null +++ b/configs/pafpn/README.md @@ -0,0 +1,26 @@ +# Path Aggregation Network for Instance Segmentation + +## Introduction + + + +``` +@inproceedings{liu2018path, + author = {Shu Liu and + Lu Qi and + Haifang Qin and + Jianping Shi and + Jiaya Jia}, + title = {Path Aggregation Network for Instance Segmentation}, + booktitle = {Proceedings of IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + year = {2018} +} +``` + +## Results and Models + +## Results and Models + +| Backbone | style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +|:-------------:|:----------:|:-------:|:--------:|:--------------:|:------:|:-------:|:------:|:--------:| +| R-50-FPN | pytorch | 1x | 4.0 | 17.2 | 37.5 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pafpn/faster_rcnn_r50_pafpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pafpn/faster_rcnn_r50_pafpn_1x_coco/faster_rcnn_r50_pafpn_1x_coco_bbox_mAP-0.375_20200503_105836-b7b4b9bd.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pafpn/faster_rcnn_r50_pafpn_1x_coco/faster_rcnn_r50_pafpn_1x_coco_20200503_105836.log.json) | diff --git a/configs/pafpn/faster_rcnn_r50_pafpn_1x_coco.py b/configs/pafpn/faster_rcnn_r50_pafpn_1x_coco.py new file mode 100644 index 0000000..b2fdef9 --- /dev/null +++ b/configs/pafpn/faster_rcnn_r50_pafpn_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' + +model = dict( + neck=dict( + type='PAFPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5)) diff --git a/configs/pafpn/metafile.yml b/configs/pafpn/metafile.yml new file mode 100644 index 0000000..f9cf97c --- /dev/null +++ b/configs/pafpn/metafile.yml @@ -0,0 +1,38 @@ +Collections: + - Name: PAFPN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - PAFPN + Paper: + URL: https://arxiv.org/abs/1803.01534 + Title: 'Path Aggregation Network for Instance Segmentation' + README: configs/pafpn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/necks/pafpn.py#L11 + Version: v2.0.0 + +Models: + - Name: faster_rcnn_r50_pafpn_1x_coco + In Collection: PAFPN + Config: configs/pafpn/faster_rcnn_r50_pafpn_1x_coco.py + Metadata: + Training Memory (GB): 4.0 + inference time (ms/im): + - value: 58.14 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pafpn/faster_rcnn_r50_pafpn_1x_coco/faster_rcnn_r50_pafpn_1x_coco_bbox_mAP-0.375_20200503_105836-b7b4b9bd.pth diff --git a/configs/panoptic_fpn/README.md b/configs/panoptic_fpn/README.md new file mode 100644 index 0000000..d209183 --- /dev/null +++ b/configs/panoptic_fpn/README.md @@ -0,0 +1,50 @@ +# Panoptic feature pyramid networks +## Introduction + + +The base method for panoptic segmentation task. + +``` +@inproceedings{kirillov2018panopticfpn, + author = { + Alexander Kirillov, + Ross Girshick, + Kaiming He, + Piotr Dollar, + }, + title = {Panoptic Feature Pyramid Networks}, + booktitle = {Proceedings of IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + year = {2019} +} +``` + +## Dataset + +PanopticFPN requires COCO and [COCO-panoptic](http://images.cocodataset.org/annotations/panoptic_annotations_trainval2017.zip) dataset for training and evaluation. You need to download and extract it in the COCO dataset path. +The directory should be like this. + +```none +mmdetection +├── mmdet +├── tools +├── configs +├── data +│ ├── coco +│ │ ├── annotations +│ │ │ ├── panoptic_train2017.json +│ │ │ ├── panoptic_train2017 +│ │ │ ├── panoptic_val2017.json +│ │ │ ├── panoptic_val2017 +│ │ ├── train2017 +│ │ ├── val2017 +│ │ ├── test2017 +``` + +## Results and Models + +| Backbone | style | Lr schd | Mem (GB) | Inf time (fps) | PQ | SQ | RQ | PQ_th | SQ_th | RQ_th | PQ_st | SQ_st | RQ_st | Config | Download | +|:-------------:|:----------:|:-------:|:--------:|:--------------:|:----:|:----:|:----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:------:|:--------:| +| R-50-FPN | pytorch | 1x | 4.7 | | 40.2 | 77.8 | 49.3 | 47.8 | 80.9 | 57.5 | 28.9 | 73.1 | 37.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco/panoptic_fpn_r50_fpn_1x_coco_20210821_101153-9668fd13.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco/panoptic_fpn_r50_fpn_1x_coco_20210821_101153.log.json) | +| R-50-FPN | pytorch | 3x | - | - | 42.5 | 78.1 | 51.7 | 50.3 | 81.5 | 60.3 | 30.7 | 73.0 | 38.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco/panoptic_fpn_r50_fpn_mstrain_3x_coco_20210824_171155-5650f98b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco/panoptic_fpn_r50_fpn_mstrain_3x_coco_20210824_171155.log.json) | +| R-101-FPN | pytorch | 1x | 6.7 | | 42.2 | 78.3 | 51.4 | 50.1 | 81.4 | 59.9 | 30.3 | 73.6 | 38.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco/panoptic_fpn_r101_fpn_1x_coco_20210820_193950-ab9157a2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco/panoptic_fpn_r101_fpn_1x_coco_20210820_193950.log.json) | +| R-101-FPN | pytorch | 3x | - | - | 44.1 | 78.9 | 53.6 | 52.1 | 81.7 | 62.3 | 32.0 | 74.6 | 40.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco/panoptic_fpn_r101_fpn_mstrain_3x_coco_20210823_114712-9c99acc4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco/panoptic_fpn_r101_fpn_mstrain_3x_coco_20210823_114712.log.json) | diff --git a/configs/panoptic_fpn/metafile.yml b/configs/panoptic_fpn/metafile.yml new file mode 100644 index 0000000..8c9d39d --- /dev/null +++ b/configs/panoptic_fpn/metafile.yml @@ -0,0 +1,70 @@ +Collections: + - Name: PanopticFPN + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - PanopticFPN + Paper: + URL: https://arxiv.org/pdf/1901.02446 + Title: 'Panoptic feature pyramid networks' + README: configs/panoptic_fpn/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.16.0/mmdet/models/detectors/panoptic_fpn.py#L7 + Version: v2.16.0 + +Models: + - Name: panoptic_fpn_r50_fpn_1x_coco + In Collection: PanopticFPN + Config: configs/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.6 + Epochs: 12 + Results: + - Task: Panoptic Segmentation + Dataset: COCO + Metrics: + PQ: 40.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco/panoptic_fpn_r50_fpn_1x_coco_20210821_101153-9668fd13.pth + + - Name: panoptic_fpn_r50_fpn_mstrain_3x_coco + In Collection: PanopticFPN + Config: configs/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 4.6 + Epochs: 36 + Results: + - Task: Panoptic Segmentation + Dataset: COCO + Metrics: + PQ: 42.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco/panoptic_fpn_r50_fpn_mstrain_3x_coco_20210824_171155-5650f98b.pth + + - Name: panoptic_fpn_r101_fpn_1x_coco + In Collection: PanopticFPN + Config: configs/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.5 + Epochs: 12 + Results: + - Task: Panoptic Segmentation + Dataset: COCO + Metrics: + PQ: 42.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco/panoptic_fpn_r101_fpn_1x_coco_20210820_193950-ab9157a2.pth + + - Name: panoptic_fpn_r101_fpn_mstrain_3x_coco + In Collection: PanopticFPN + Config: configs/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 6.5 + Epochs: 36 + Results: + - Task: Panoptic Segmentation + Dataset: COCO + Metrics: + PQ: 44.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco/panoptic_fpn_r101_fpn_mstrain_3x_coco_20210823_114712-9c99acc4.pth diff --git a/configs/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco.py b/configs/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco.py new file mode 100644 index 0000000..78b8079 --- /dev/null +++ b/configs/panoptic_fpn/panoptic_fpn_r101_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = './panoptic_fpn_r50_fpn_1x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco.py b/configs/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..057e481 --- /dev/null +++ b/configs/panoptic_fpn/panoptic_fpn_r101_fpn_mstrain_3x_coco.py @@ -0,0 +1,6 @@ +_base_ = './panoptic_fpn_r50_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco.py b/configs/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..2995524 --- /dev/null +++ b/configs/panoptic_fpn/panoptic_fpn_r50_fpn_1x_coco.py @@ -0,0 +1,33 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_panoptic.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='PanopticFPN', + semantic_head=dict( + type='PanopticFPNHead', + num_things_classes=80, + num_stuff_classes=53, + in_channels=256, + inner_channels=128, + start_level=0, + end_level=4, + norm_cfg=dict(type='GN', num_groups=32, requires_grad=True), + conv_cfg=None, + loss_seg=dict( + type='CrossEntropyLoss', ignore_index=255, loss_weight=0.5)), + panoptic_fusion_head=dict( + type='HeuristicFusionHead', + num_things_classes=80, + num_stuff_classes=53), + test_cfg=dict( + panoptic=dict( + score_thr=0.6, + max_per_img=100, + mask_thr_binary=0.5, + mask_overlap=0.5, + nms=dict(type='nms', iou_threshold=0.5, class_agnostic=True), + stuff_area_limit=4096))) + +custom_hooks = [] diff --git a/configs/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco.py b/configs/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..b510935 --- /dev/null +++ b/configs/panoptic_fpn/panoptic_fpn_r50_fpn_mstrain_3x_coco.py @@ -0,0 +1,61 @@ +_base_ = './panoptic_fpn_r50_fpn_1x_coco.py' + +# dataset settings +dataset_type = 'CocoPanopticDataset' +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) + +# In mstrain 3x config, img_scale=[(1333, 640), (1333, 800)], +# multiscale_mode='range' +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='LoadPanopticAnnotations', + with_bbox=True, + with_mask=True, + with_seg=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='SegRescale', scale_factor=1 / 4), + dict(type='DefaultFormatBundle'), + dict( + type='Collect', + keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks', 'gt_semantic_seg']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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']), + ]) +] + +# Use RepeatDataset to speed up training +data = dict( + train=dict( + _delete_=True, + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file=data_root + 'annotations/panoptic_train2017.json', + img_prefix=data_root + 'train2017/', + seg_prefix=data_root + 'annotations/panoptic_train2017/', + pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/pascal_voc/README.md b/configs/pascal_voc/README.md new file mode 100644 index 0000000..69e0220 --- /dev/null +++ b/configs/pascal_voc/README.md @@ -0,0 +1,23 @@ +# PASCAL VOC Dataset + + + +``` +@Article{Everingham10, + author = "Everingham, M. and Van~Gool, L. and Williams, C. K. I. and Winn, J. and Zisserman, A.", + title = "The Pascal Visual Object Classes (VOC) Challenge", + journal = "International Journal of Computer Vision", + volume = "88", + year = "2010", + number = "2", + month = jun, + pages = "303--338", +} +``` + +## Results and Models + +| Architecture | Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:------------:|:---------:|:-------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| Faster R-CNN | R-50 | pytorch | 1x | 2.6 | - | 79.5 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712/faster_rcnn_r50_fpn_1x_voc0712_20200624-c9895d40.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712/20200623_015208.log.json) | +| Retinanet | R-50 | pytorch | 1x | 2.1 | - | 77.3 |[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pascal_voc/retinanet_r50_fpn_1x_voc0712.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pascal_voc/retinanet_r50_fpn_1x_voc0712/retinanet_r50_fpn_1x_voc0712_20200617-47cbdd0e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pascal_voc/retinanet_r50_fpn_1x_voc0712/retinanet_r50_fpn_1x_voc0712_20200616_014642.log.json) | diff --git a/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712.py b/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712.py new file mode 100644 index 0000000..7866ace --- /dev/null +++ b/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712.py @@ -0,0 +1,14 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', '../_base_/datasets/voc0712.py', + '../_base_/default_runtime.py' +] +model = dict(roi_head=dict(bbox_head=dict(num_classes=20))) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +# actual epoch = 3 * 3 = 9 +lr_config = dict(policy='step', step=[3]) +# runtime settings +runner = dict( + type='EpochBasedRunner', max_epochs=4) # actual epoch = 4 * 3 = 12 diff --git a/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712_cocofmt.py b/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712_cocofmt.py new file mode 100644 index 0000000..12eee2c --- /dev/null +++ b/configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc0712_cocofmt.py @@ -0,0 +1,75 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', '../_base_/datasets/voc0712.py', + '../_base_/default_runtime.py' +] +model = dict(roi_head=dict(bbox_head=dict(num_classes=20))) + +CLASSES = ('aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', + 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', + 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor') + +# dataset settings +dataset_type = 'CocoDataset' +data_root = 'data/VOCdevkit/' +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), + 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), + 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=2, + workers_per_gpu=2, + train=dict( + type='RepeatDataset', + times=3, + dataset=dict( + type=dataset_type, + ann_file='data/voc0712_trainval.json', + img_prefix='data/VOCdevkit', + pipeline=train_pipeline, + classes=CLASSES)), + val=dict( + type=dataset_type, + ann_file='data/voc07_test.json', + img_prefix='data/VOCdevkit', + pipeline=test_pipeline, + classes=CLASSES), + test=dict( + type=dataset_type, + ann_file='data/voc07_test.json', + img_prefix='data/VOCdevkit', + pipeline=test_pipeline, + classes=CLASSES)) +evaluation = dict(interval=1, metric='bbox') + +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +# actual epoch = 3 * 3 = 9 +lr_config = dict(policy='step', step=[3]) +# runtime settings +runner = dict( + type='EpochBasedRunner', max_epochs=4) # actual epoch = 4 * 3 = 12 diff --git a/configs/pascal_voc/retinanet_r50_fpn_1x_voc0712.py b/configs/pascal_voc/retinanet_r50_fpn_1x_voc0712.py new file mode 100644 index 0000000..b4b050d --- /dev/null +++ b/configs/pascal_voc/retinanet_r50_fpn_1x_voc0712.py @@ -0,0 +1,14 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', '../_base_/datasets/voc0712.py', + '../_base_/default_runtime.py' +] +model = dict(bbox_head=dict(num_classes=20)) +# optimizer +optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001) +optimizer_config = dict(grad_clip=None) +# learning policy +# actual epoch = 3 * 3 = 9 +lr_config = dict(policy='step', step=[3]) +# runtime settings +runner = dict( + type='EpochBasedRunner', max_epochs=4) # actual epoch = 4 * 3 = 12 diff --git a/configs/pascal_voc/ssd300_voc0712.py b/configs/pascal_voc/ssd300_voc0712.py new file mode 100644 index 0000000..271ebe3 --- /dev/null +++ b/configs/pascal_voc/ssd300_voc0712.py @@ -0,0 +1,69 @@ +_base_ = [ + '../_base_/models/ssd300.py', '../_base_/datasets/voc0712.py', + '../_base_/default_runtime.py' +] +model = dict( + bbox_head=dict( + num_classes=20, anchor_generator=dict(basesize_ratio_range=(0.2, + 0.9)))) +# dataset settings +dataset_type = 'VOCDataset' +data_root = 'data/VOCdevkit/' +img_norm_cfg = dict(mean=[123.675, 116.28, 103.53], std=[1, 1, 1], to_rgb=True) +train_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='Expand', + mean=img_norm_cfg['mean'], + to_rgb=img_norm_cfg['to_rgb'], + ratio_range=(1, 4)), + dict( + type='MinIoURandomCrop', + min_ious=(0.1, 0.3, 0.5, 0.7, 0.9), + min_crop_size=0.3), + dict(type='Resize', img_scale=(300, 300), keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(300, 300), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + samples_per_gpu=8, + workers_per_gpu=3, + train=dict( + type='RepeatDataset', times=10, dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +# optimizer +optimizer = dict(type='SGD', lr=1e-3, momentum=0.9, weight_decay=5e-4) +optimizer_config = dict() +# learning policy +lr_config = dict( + policy='step', + warmup='linear', + warmup_iters=500, + warmup_ratio=0.001, + step=[16, 20]) +checkpoint_config = dict(interval=1) +# runtime settings +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/pascal_voc/ssd512_voc0712.py b/configs/pascal_voc/ssd512_voc0712.py new file mode 100644 index 0000000..ea2b69f --- /dev/null +++ b/configs/pascal_voc/ssd512_voc0712.py @@ -0,0 +1,52 @@ +_base_ = 'ssd300_voc0712.py' +input_size = 512 +model = dict( + bbox_head=dict( + in_channels=(512, 1024, 512, 256, 256, 256, 256), + anchor_generator=dict( + input_size=input_size, + strides=[8, 16, 32, 64, 128, 256, 512], + basesize_ratio_range=(0.15, 0.9), + ratios=([2], [2, 3], [2, 3], [2, 3], [2, 3], [2], [2])))) +img_norm_cfg = dict(mean=[123.675, 116.28, 103.53], std=[1, 1, 1], to_rgb=True) +train_pipeline = [ + dict(type='LoadImageFromFile', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='PhotoMetricDistortion', + brightness_delta=32, + contrast_range=(0.5, 1.5), + saturation_range=(0.5, 1.5), + hue_delta=18), + dict( + type='Expand', + mean=img_norm_cfg['mean'], + to_rgb=img_norm_cfg['to_rgb'], + ratio_range=(1, 4)), + dict( + type='MinIoURandomCrop', + min_ious=(0.1, 0.3, 0.5, 0.7, 0.9), + min_crop_size=0.3), + dict(type='Resize', img_scale=(512, 512), keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(512, 512), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=False), + dict(type='Normalize', **img_norm_cfg), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] +data = dict( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) diff --git a/configs/pisa/README.md b/configs/pisa/README.md new file mode 100644 index 0000000..3ae3392 --- /dev/null +++ b/configs/pisa/README.md @@ -0,0 +1,40 @@ +# Prime Sample Attention in Object Detection + +## Introduction + + + +```latex +@inproceedings{cao2019prime, + title={Prime sample attention in object detection}, + author={Cao, Yuhang and Chen, Kai and Loy, Chen Change and Lin, Dahua}, + booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, + year={2020} +} +``` + +## Results and models + +| PISA | Network | Backbone | Lr schd | box AP | mask AP | Config | Download | +|:----:|:-------:|:-------------------:|:-------:|:------:|:-------:|:------:|:--------:| +| × | Faster R-CNN | R-50-FPN | 1x | 36.4 | | - | +| √ | Faster R-CNN | R-50-FPN | 1x | 38.4 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_faster_rcnn_r50_fpn_1x_coco/pisa_faster_rcnn_r50_fpn_1x_coco-dea93523.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_faster_rcnn_r50_fpn_1x_coco/pisa_faster_rcnn_r50_fpn_1x_coco_20200506_185619.log.json) | +| × | Faster R-CNN | X101-32x4d-FPN | 1x | 40.1 | | - | +| √ | Faster R-CNN | X101-32x4d-FPN | 1x | 41.9 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco-e4accec4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco_20200505_181503.log.json) | +| × | Mask R-CNN | R-50-FPN | 1x | 37.3 | 34.2 | - | +| √ | Mask R-CNN | R-50-FPN | 1x | 39.1 | 35.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_mask_rcnn_r50_fpn_1x_coco/pisa_mask_rcnn_r50_fpn_1x_coco-dfcedba6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_mask_rcnn_r50_fpn_1x_coco/pisa_mask_rcnn_r50_fpn_1x_coco_20200508_150500.log.json) | +| × | Mask R-CNN | X101-32x4d-FPN | 1x | 41.1 | 37.1 | - | +| √ | Mask R-CNN | X101-32x4d-FPN | 1x | | | | +| × | RetinaNet | R-50-FPN | 1x | 35.6 | | - | +| √ | RetinaNet | R-50-FPN | 1x | 36.9 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_retinanet_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_retinanet_r50_fpn_1x_coco/pisa_retinanet_r50_fpn_1x_coco-76409952.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_retinanet_r50_fpn_1x_coco/pisa_retinanet_r50_fpn_1x_coco_20200504_014311.log.json) | +| × | RetinaNet | X101-32x4d-FPN | 1x | 39.0 | | - | +| √ | RetinaNet | X101-32x4d-FPN | 1x | 40.7 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco/pisa_retinanet_x101_32x4d_fpn_1x_coco-a0c13c73.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco/pisa_retinanet_x101_32x4d_fpn_1x_coco_20200505_001404.log.json) | +| × | SSD300 | VGG16 | 1x | 25.6 | | - | +| √ | SSD300 | VGG16 | 1x | 27.6 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_ssd300_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_ssd300_coco/pisa_ssd300_coco-710e3ac9.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_ssd300_coco/pisa_ssd300_coco_20200504_144325.log.json) | +| × | SSD300 | VGG16 | 1x | 29.3 | | - | +| √ | SSD300 | VGG16 | 1x | 31.8 | | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pisa/pisa_ssd512_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_ssd512_coco/pisa_ssd512_coco-247addee.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_ssd512_coco/pisa_ssd512_coco_20200508_131030.log.json) | + +**Notes:** + +- In the original paper, all models are trained and tested on mmdet v1.x, thus results may not be exactly the same with this release on v2.0. +- It is noted PISA only modifies the training pipeline so the inference time remains the same with the baseline. diff --git a/configs/pisa/metafile.yml b/configs/pisa/metafile.yml new file mode 100644 index 0000000..cd43afb --- /dev/null +++ b/configs/pisa/metafile.yml @@ -0,0 +1,110 @@ +Collections: + - Name: PISA + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - PISA + - RPN + - ResNet + - RoIPool + Paper: + URL: https://arxiv.org/abs/1904.04821 + Title: 'Prime Sample Attention in Object Detection' + README: configs/pisa/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.1.0/mmdet/models/roi_heads/pisa_roi_head.py#L8 + Version: v2.1.0 + +Models: + - Name: pisa_faster_rcnn_r50_fpn_1x_coco + In Collection: PISA + Config: configs/pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_faster_rcnn_r50_fpn_1x_coco/pisa_faster_rcnn_r50_fpn_1x_coco-dea93523.pth + + - Name: pisa_faster_rcnn_x101_32x4d_fpn_1x_coco + In Collection: PISA + Config: configs/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco-e4accec4.pth + + - Name: pisa_mask_rcnn_r50_fpn_1x_coco + In Collection: PISA + Config: configs/pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 35.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_mask_rcnn_r50_fpn_1x_coco/pisa_mask_rcnn_r50_fpn_1x_coco-dfcedba6.pth + + - Name: pisa_retinanet_r50_fpn_1x_coco + In Collection: PISA + Config: configs/pisa/pisa_retinanet_r50_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_retinanet_r50_fpn_1x_coco/pisa_retinanet_r50_fpn_1x_coco-76409952.pth + + - Name: pisa_retinanet_x101_32x4d_fpn_1x_coco + In Collection: PISA + Config: configs/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco/pisa_retinanet_x101_32x4d_fpn_1x_coco-a0c13c73.pth + + - Name: pisa_ssd300_coco + In Collection: PISA + Config: configs/pisa/pisa_ssd300_coco.py + Metadata: + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 27.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_ssd300_coco/pisa_ssd300_coco-710e3ac9.pth + + - Name: pisa_ssd512_coco + In Collection: PISA + Config: configs/pisa/pisa_ssd512_coco.py + Metadata: + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 31.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pisa/pisa_ssd512_coco/pisa_ssd512_coco-247addee.pth diff --git a/configs/pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py b/configs/pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..71e65b0 --- /dev/null +++ b/configs/pisa/pisa_faster_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,30 @@ +_base_ = '../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py' + +model = dict( + roi_head=dict( + type='PISARoIHead', + bbox_head=dict( + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + train_cfg=dict( + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + sampler=dict( + type='ScoreHLRSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True, + k=0.5, + bias=0.), + isr=dict(k=2, bias=0), + carl=dict(k=1, bias=0.2))), + test_cfg=dict( + rpn=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0))) diff --git a/configs/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..16edd99 --- /dev/null +++ b/configs/pisa/pisa_faster_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,30 @@ +_base_ = '../faster_rcnn/faster_rcnn_x101_32x4d_fpn_1x_coco.py' + +model = dict( + roi_head=dict( + type='PISARoIHead', + bbox_head=dict( + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + train_cfg=dict( + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + sampler=dict( + type='ScoreHLRSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True, + k=0.5, + bias=0.), + isr=dict(k=2, bias=0), + carl=dict(k=1, bias=0.2))), + test_cfg=dict( + rpn=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0))) diff --git a/configs/pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py b/configs/pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py new file mode 100644 index 0000000..047a293 --- /dev/null +++ b/configs/pisa/pisa_mask_rcnn_r50_fpn_1x_coco.py @@ -0,0 +1,30 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py' + +model = dict( + roi_head=dict( + type='PISARoIHead', + bbox_head=dict( + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + train_cfg=dict( + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + sampler=dict( + type='ScoreHLRSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True, + k=0.5, + bias=0.), + isr=dict(k=2, bias=0), + carl=dict(k=1, bias=0.2))), + test_cfg=dict( + rpn=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0))) diff --git a/configs/pisa/pisa_mask_rcnn_x101_32x4d_fpn_1x_coco.py b/configs/pisa/pisa_mask_rcnn_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..2186a8f --- /dev/null +++ b/configs/pisa/pisa_mask_rcnn_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,30 @@ +_base_ = '../mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py' + +model = dict( + roi_head=dict( + type='PISARoIHead', + bbox_head=dict( + loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))), + train_cfg=dict( + rpn_proposal=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + sampler=dict( + type='ScoreHLRSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True, + k=0.5, + bias=0.), + isr=dict(k=2, bias=0), + carl=dict(k=1, bias=0.2))), + test_cfg=dict( + rpn=dict( + nms_pre=2000, + max_per_img=2000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0))) diff --git a/configs/pisa/pisa_retinanet_r50_fpn_1x_coco.py b/configs/pisa/pisa_retinanet_r50_fpn_1x_coco.py new file mode 100644 index 0000000..70f89e2 --- /dev/null +++ b/configs/pisa/pisa_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = '../retinanet/retinanet_r50_fpn_1x_coco.py' + +model = dict( + bbox_head=dict( + type='PISARetinaHead', + loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0)), + train_cfg=dict(isr=dict(k=2., bias=0.), carl=dict(k=1., bias=0.2))) diff --git a/configs/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco.py b/configs/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco.py new file mode 100644 index 0000000..b97b672 --- /dev/null +++ b/configs/pisa/pisa_retinanet_x101_32x4d_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = '../retinanet/retinanet_x101_32x4d_fpn_1x_coco.py' + +model = dict( + bbox_head=dict( + type='PISARetinaHead', + loss_bbox=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0)), + train_cfg=dict(isr=dict(k=2., bias=0.), carl=dict(k=1., bias=0.2))) diff --git a/configs/pisa/pisa_ssd300_coco.py b/configs/pisa/pisa_ssd300_coco.py new file mode 100644 index 0000000..b5cc006 --- /dev/null +++ b/configs/pisa/pisa_ssd300_coco.py @@ -0,0 +1,8 @@ +_base_ = '../ssd/ssd300_coco.py' + +model = dict( + bbox_head=dict(type='PISASSDHead'), + train_cfg=dict(isr=dict(k=2., bias=0.), carl=dict(k=1., bias=0.2))) + +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/pisa/pisa_ssd512_coco.py b/configs/pisa/pisa_ssd512_coco.py new file mode 100644 index 0000000..3219d6d --- /dev/null +++ b/configs/pisa/pisa_ssd512_coco.py @@ -0,0 +1,8 @@ +_base_ = '../ssd/ssd512_coco.py' + +model = dict( + bbox_head=dict(type='PISASSDHead'), + train_cfg=dict(isr=dict(k=2., bias=0.), carl=dict(k=1., bias=0.2))) + +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/pix2seq/README.md b/configs/pix2seq/README.md new file mode 100644 index 0000000..c6b3f20 --- /dev/null +++ b/configs/pix2seq/README.md @@ -0,0 +1,21 @@ +# Pix2seq + +## Introduction + + + +We provide the config files for Pix2seq: [Pix2seq: A Language Modeling Framework for Object Detection](https://arxiv.org/abs/2109.10852). + +```BibTeX +@article{chen2021pix2seq, + title={Pix2seq: A language modeling framework for object detection}, + author={Chen, Ting and Saxena, Saurabh and Li, Lala and Fleet, David J and Hinton, Geoffrey}, + journal={arXiv preprint arXiv:2109.10852}, + year={2021} +} +``` + +## Results and Models + +| Backbone | Model | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:------:|:--------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| diff --git a/configs/pix2seq/metafile.yml b/configs/pix2seq/metafile.yml new file mode 100644 index 0000000..31c7be9 --- /dev/null +++ b/configs/pix2seq/metafile.yml @@ -0,0 +1,33 @@ +Collections: + - Name: Pix2seq + Metadata: + Training Data: COCO + Training Techniques: + - AdamW + - Multi Scale Train + - Gradient Clip + Training Resources: 8x V100 GPUs + Architecture: + - ResNet + - Transformer + Paper: + URL: https://arxiv.org/abs/2109.10852 + Title: 'Pix2seq: A Language Modeling Framework for Object Detection' + README: configs/pix2seq/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.7.0/mmdet/models/detectors/pix2seq.py + Version: v1.0.0 + +Models: + - Name: pix2seq_r50_4x2_50e_coco + In Collection: Pix2seq + Config: configs/pix2seq/pix2seq_r50_4x2_50e_coco.py + Metadata: + Training Memory (GB): 7.9 + Epochs: 300 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.0 + Weights: https://drive.google.com/file/d/1Ku8ZORiLtMs66uleS3aXId7pxlJrTK9d/view?usp=sharing diff --git a/configs/pix2seq/pix2seq_r50_8x4_300e_coco.py b/configs/pix2seq/pix2seq_r50_8x4_300e_coco.py new file mode 100644 index 0000000..cfdd142 --- /dev/null +++ b/configs/pix2seq/pix2seq_r50_8x4_300e_coco.py @@ -0,0 +1,156 @@ +_base_ = [ + '../_base_/datasets/coco_detection_pix2seq.py', '../_base_/default_runtime.py' +] +model = dict( + type='Pix2seq', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(3, ), + frozen_stages=0, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, # Frozen BN weight and bias + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + bbox_head=dict( + type='Pix2seqHead', + num_classes=91, + in_channels=2048, + num_vocal=2094, + rand_target=True, + drop_token=True, + random_token=True, + split_loss=False, + transformer=dict( + type='Pix2seqTransformer', + encoder=dict( + type='DetrTransformerEncoder', + num_layers=6, + transformerlayers=dict( + type='BaseTransformerLayer', + attn_cfgs=[ + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1) + ], + feedforward_channels=1024, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'ffn', 'norm'))), + decoder=dict( + type='Pix2seqTransformerDecoder', + num_layers=6, + post_norm_cfg=dict(type='LN'), + transformerlayers=dict( + type='Pix2seqTransformerDecoderLayer', + attn_cfgs=[ + dict( + type='Pix2seqAttention', + embed_dims=256, + num_heads=8, + dropout=0.1, + self_attn_dropout=0.1), + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1) + ], + feedforward_channels=1024, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'cross_attn', 'norm', + 'ffn', 'norm')), + ), + ), + positional_encoding=dict( + type='SinePositionalEncoding', num_feats=128, normalize=False))) +# augment +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', to_float32=True), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='RandomDistortion', + brightness=0.5, + contrast=0.5, + saturation=0.5, + hue=0.5), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(0.3, 2.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']) +] +# test_pipeline, NOTE the Pad's size_divisor is different from the default +# setting (size_divisor=32). While there is little effect on the performance +# whether we use the default setting or use size_divisor=1. +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 1333), + flip=False, + transforms=[ + dict( + type='LargeScaleJitter', + desired_size=1333, + ratio_range=(1.0, 1.0), + keep_ratio=True, + allow_negative_crop=True), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1), + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']) + ]) +] +# dataset +dataset_type = 'Pix2seqCocoDataset' +data_root = 'data/coco/' +data = dict( + samples_per_gpu=4, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_train2017.json', + img_prefix=data_root + 'train2017/', + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline), + test=dict( + type=dataset_type, + ann_file=data_root + 'annotations/instances_val2017.json', + img_prefix=data_root + 'val2017/', + pipeline=test_pipeline) +) +# optimizer +optimizer = dict( + type='AdamW', + lr=1e-3, + weight_decay=0.05, + paramwise_cfg=dict( + custom_keys={'backbone': dict(lr_mult=0.1, decay_mult=1.0)})) +optimizer_config = dict(grad_clip=dict(max_norm=0.1, norm_type=2)) +runner = dict(type='EpochBasedRunner', max_epochs=300) +fp16 = dict(loss_scale='dynamic') +checkpoint_config = dict(interval=50) +lr_config = dict( + policy='LinearlyDecay', + warmup='linear', + by_epoch=True, + warmup_by_epoch=True, + warmup_ratio=0.01, + warmup_iters=10, # 10 epoch + min_lr_ratio=0.01) +evaluation = dict(interval=10, metric='bbox') \ No newline at end of file diff --git a/configs/point_rend/README.md b/configs/point_rend/README.md new file mode 100644 index 0000000..fafb29c --- /dev/null +++ b/configs/point_rend/README.md @@ -0,0 +1,23 @@ +# PointRend + +## Introduction + + + +```latex +@InProceedings{kirillov2019pointrend, + title={{PointRend}: Image Segmentation as Rendering}, + author={Alexander Kirillov and Yuxin Wu and Kaiming He and Ross Girshick}, + journal={ArXiv:1912.08193}, + year={2019} +} +``` + +## Results and models + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-------------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| R-50-FPN | caffe | 1x | 4.6 | | 38.4 | 36.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco/point_rend_r50_caffe_fpn_mstrain_1x_coco-1bcb5fb4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco/point_rend_r50_caffe_fpn_mstrain_1x_coco_20200612_161407.log.json) | +| R-50-FPN | caffe | 3x | 4.6 | | 41.0 | 38.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco/point_rend_r50_caffe_fpn_mstrain_3x_coco-e0ebb6b7.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco/point_rend_r50_caffe_fpn_mstrain_3x_coco_20200614_002632.log.json) | + +Note: All models are trained with multi-scale, the input image shorter side is randomly scaled to one of (640, 672, 704, 736, 768, 800). diff --git a/configs/point_rend/metafile.yml b/configs/point_rend/metafile.yml new file mode 100644 index 0000000..82aea05 --- /dev/null +++ b/configs/point_rend/metafile.yml @@ -0,0 +1,54 @@ +Collections: + - Name: PointRend + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - PointRend + - FPN + - ResNet + Paper: + URL: https://arxiv.org/abs/1912.08193 + Title: 'PointRend: Image Segmentation as Rendering' + README: configs/point_rend/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.2.0/mmdet/models/detectors/point_rend.py#L6 + Version: v2.2.0 + +Models: + - Name: point_rend_r50_caffe_fpn_mstrain_1x_coco + In Collection: PointRend + Config: configs/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco.py + Metadata: + Training Memory (GB): 4.6 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco/point_rend_r50_caffe_fpn_mstrain_1x_coco-1bcb5fb4.pth + + - Name: point_rend_r50_caffe_fpn_mstrain_3x_coco + In Collection: PointRend + Config: configs/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 4.6 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco/point_rend_r50_caffe_fpn_mstrain_3x_coco-e0ebb6b7.pth diff --git a/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco.py b/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco.py new file mode 100644 index 0000000..0c0e563 --- /dev/null +++ b/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_1x_coco.py @@ -0,0 +1,44 @@ +_base_ = '../mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain_1x_coco.py' +# model settings +model = dict( + type='PointRend', + roi_head=dict( + type='PointRendRoIHead', + mask_roi_extractor=dict( + type='GenericRoIExtractor', + aggregation='concat', + roi_layer=dict( + _delete_=True, type='SimpleRoIAlign', output_size=14), + out_channels=256, + featmap_strides=[4]), + mask_head=dict( + _delete_=True, + type='CoarseMaskHead', + num_fcs=2, + in_channels=256, + conv_out_channels=256, + fc_out_channels=1024, + num_classes=80, + loss_mask=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0)), + point_head=dict( + type='MaskPointHead', + num_fcs=3, + in_channels=256, + fc_channels=256, + num_classes=80, + coarse_pred_each_layer=True, + loss_point=dict( + type='CrossEntropyLoss', use_mask=True, loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rcnn=dict( + mask_size=7, + num_points=14 * 14, + oversample_ratio=3, + importance_sample_ratio=0.75)), + test_cfg=dict( + rcnn=dict( + subdivision_steps=5, + subdivision_num_points=28 * 28, + scale_factor=2))) diff --git a/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco.py b/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..169278e --- /dev/null +++ b/configs/point_rend/point_rend_r50_caffe_fpn_mstrain_3x_coco.py @@ -0,0 +1,4 @@ +_base_ = './point_rend_r50_caffe_fpn_mstrain_1x_coco.py' +# learning policy +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/pvt/README.md b/configs/pvt/README.md new file mode 100644 index 0000000..99ace87 --- /dev/null +++ b/configs/pvt/README.md @@ -0,0 +1,43 @@ +# Pyramid vision transformer: A versatile backbone for dense prediction without convolutions + +## Introduction + + + +```latex +@article{wang2021pyramid, + title={Pyramid vision transformer: A versatile backbone for dense prediction without convolutions}, + author={Wang, Wenhai and Xie, Enze and Li, Xiang and Fan, Deng-Ping and Song, Kaitao and Liang, Ding and Lu, Tong and Luo, Ping and Shao, Ling}, + journal={arXiv preprint arXiv:2102.12122}, + year={2021} +} +``` + +```latex +@article{wang2021pvtv2, + title={PVTv2: Improved Baselines with Pyramid Vision Transformer}, + author={Wang, Wenhai and Xie, Enze and Li, Xiang and Fan, Deng-Ping and Song, Kaitao and Liang, Ding and Lu, Tong and Luo, Ping and Shao, Ling}, + journal={arXiv preprint arXiv:2106.13797}, + year={2021} +} +``` +## Results and Models + +### RetinaNet (PVTv1) + +| Backbone | Lr schd | Mem (GB) | box AP | Config | Download | +|:-----------:|:-------:|:--------:|:------:|:------:|:--------:| +| PVT-Tiny | 12e |8.5 |36.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_t_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-t_fpn_1x_coco/retinanet_pvt-t_fpn_1x_coco_20210831_103110-17b566bd.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-t_fpn_1x_coco/retinanet_pvt-t_fpn_1x_coco_20210831_103110.log.json) | +| PVT-Small | 12e |14.5 |40.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_s_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-s_fpn_1x_coco/retinanet_pvt-s_fpn_1x_coco_20210906_142921-b6c94a5b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-s_fpn_1x_coco/retinanet_pvt-s_fpn_1x_coco_20210906_142921.log.json) | +| PVT-Medium | 12e |20.9 |41.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_m_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-m_fpn_1x_coco/retinanet_pvt-m_fpn_1x_coco_20210831_103243-55effa1b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-m_fpn_1x_coco/retinanet_pvt-m_fpn_1x_coco_20210831_103243.log.json) | + +### RetinaNet (PVTv2) + +| Backbone | Lr schd | Mem (GB) | box AP | Config | Download | +|:-----------:|:-------:|:--------:|:------:|:------:|:--------:| +| PVTv2-B0 | 12e |7.4 |37.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_v2_b0_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b0_fpn_1x_coco/retinanet_pvtv2-b0_fpn_1x_coco_20210831_103157-13e9aabe.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b0_fpn_1x_coco/retinanet_pvtv2-b0_fpn_1x_coco_20210831_103157.log.json) | +| PVTv2-B1 | 12e |9.5 |41.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_v2_b1_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b1_fpn_1x_coco/retinanet_pvtv2-b1_fpn_1x_coco_20210831_103318-7e169a7d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b1_fpn_1x_coco/retinanet_pvtv2-b1_fpn_1x_coco_20210831_103318.log.json) | +| PVTv2-B2 | 12e |16.2 |44.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_v2_b2_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b2_fpn_1x_coco/retinanet_pvtv2-b2_fpn_1x_coco_20210901_174843-529f0b9a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b2_fpn_1x_coco/retinanet_pvtv2-b2_fpn_1x_coco_20210901_174843.log.json) | +| PVTv2-B3 | 12e |23.0 |46.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_v2_b3_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b3_fpn_1x_coco/retinanet_pvtv2-b3_fpn_1x_coco_20210903_151512-8357deff.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b3_fpn_1x_coco/retinanet_pvtv2-b3_fpn_1x_coco_20210903_151512.log.json) | +| PVTv2-B4 | 12e |17.0 |46.3 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_v2_b4_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b4_fpn_1x_coco/retinanet_pvtv2-b4_fpn_1x_coco_20210901_170151-83795c86.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b4_fpn_1x_coco/retinanet_pvtv2-b4_fpn_1x_coco_20210901_170151.log.json) | +| PVTv2-B5 | 12e |18.7 |46.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/pvt/retinanet_pvt_v2_b5_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b5_fpn_1x_coco/retinanet_pvtv2-b5_fpn_1x_coco_20210902_201800-3420eb57.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b5_fpn_1x_coco/retinanet_pvtv2-b5_fpn_1x_coco_20210902_201800.log.json) | diff --git a/configs/pvt/metafile.yml b/configs/pvt/metafile.yml new file mode 100644 index 0000000..48a0e2c --- /dev/null +++ b/configs/pvt/metafile.yml @@ -0,0 +1,136 @@ +Collections: + - Name: PVT + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x NVIDIA V100 GPUs + Architecture: + - RetinaNet + - PyramidVisionTransformer + - FPN + Paper: https://arxiv.org/abs/2102.12122 + README: configs/pvt/README.md + - Name: PVT-v2 + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x NVIDIA V100 GPUs + Architecture: + - RetinaNet + - PyramidVisionTransformerV2 + - FPN + Paper: https://arxiv.org/abs/2106.13797 + README: configs/pvt/README.md +Models: + - Name: retinanet_pvt-t_fpn_1x_coco + In Collection: PVT + Config: configs/pvt/retinanet_pvt-t_fpn_1x_coco.py + Metadata: + Training Memory (GB): 8.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-t_fpn_1x_coco/retinanet_pvt-t_fpn_1x_coco_20210831_103110-17b566bd.pth + - Name: retinanet_pvt-s_fpn_1x_coco + In Collection: PVT + Config: configs/pvt/retinanet_pvt-s_fpn_1x_coco.py + Metadata: + Training Memory (GB): 14.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-s_fpn_1x_coco/retinanet_pvt-s_fpn_1x_coco_20210906_142921-b6c94a5b.pth + - Name: retinanet_pvt-m_fpn_1x_coco + In Collection: PVT + Config: configs/pvt/retinanet_pvt-m_fpn_1x_coco.py + Metadata: + Training Memory (GB): 20.9 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvt-m_fpn_1x_coco/retinanet_pvt-m_fpn_1x_coco_20210831_103243-55effa1b.pth + - Name: retinanet_pvtv2-b0_fpn_1x_coco + In Collection: PVT-v2 + Config: configs/pvt/retinanet_pvtv2-b0_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.4 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b0_fpn_1x_coco/retinanet_pvtv2-b0_fpn_1x_coco_20210831_103157-13e9aabe.pth + - Name: retinanet_pvtv2-b1_fpn_1x_coco + In Collection: PVT-v2 + Config: configs/pvt/retinanet_pvtv2-b1_fpn_1x_coco.py + Metadata: + Training Memory (GB): 9.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b1_fpn_1x_coco/retinanet_pvtv2-b1_fpn_1x_coco_20210831_103318-7e169a7d.pth + - Name: retinanet_pvtv2-b2_fpn_1x_coco + In Collection: PVT-v2 + Config: configs/pvt/retinanet_pvtv2-b2_fpn_1x_coco.py + Metadata: + Training Memory (GB): 16.2 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b2_fpn_1x_coco/retinanet_pvtv2-b2_fpn_1x_coco_20210901_174843-529f0b9a.pth + - Name: retinanet_pvtv2-b3_fpn_1x_coco + In Collection: PVT-v2 + Config: configs/pvt/retinanet_pvtv2-b3_fpn_1x_coco.py + Metadata: + Training Memory (GB): 23.0 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b3_fpn_1x_coco/retinanet_pvtv2-b3_fpn_1x_coco_20210903_151512-8357deff.pth + - Name: retinanet_pvtv2-b4_fpn_1x_coco + In Collection: PVT-v2 + Config: configs/pvt/retinanet_pvtv2-b4_fpn_1x_coco.py + Metadata: + Training Memory (GB): 17.0 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b4_fpn_1x_coco/retinanet_pvtv2-b4_fpn_1x_coco_20210901_170151-83795c86.pth + - Name: retinanet_pvtv2-b5_fpn_1x_coco + In Collection: PVT-v2 + Config: configs/pvt/retinanet_pvtv2-b5_fpn_1x_coco.py + Metadata: + Training Memory (GB): 18.7 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/pvt/retinanet_pvtv2-b5_fpn_1x_coco/retinanet_pvtv2-b5_fpn_1x_coco_20210902_201800-3420eb57.pth diff --git a/configs/pvt/retinanet_pvt-l_fpn_1x_coco.py b/configs/pvt/retinanet_pvt-l_fpn_1x_coco.py new file mode 100644 index 0000000..e299f2a --- /dev/null +++ b/configs/pvt/retinanet_pvt-l_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = 'retinanet_pvt-t_fpn_1x_coco.py' +model = dict( + backbone=dict( + num_layers=[3, 8, 27, 3], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_large.pth'))) +fp16 = dict(loss_scale=dict(init_scale=512)) diff --git a/configs/pvt/retinanet_pvt-m_fpn_1x_coco.py b/configs/pvt/retinanet_pvt-m_fpn_1x_coco.py new file mode 100644 index 0000000..b888f78 --- /dev/null +++ b/configs/pvt/retinanet_pvt-m_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = 'retinanet_pvt-t_fpn_1x_coco.py' +model = dict( + backbone=dict( + num_layers=[3, 4, 18, 3], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_medium.pth'))) diff --git a/configs/pvt/retinanet_pvt-s_fpn_1x_coco.py b/configs/pvt/retinanet_pvt-s_fpn_1x_coco.py new file mode 100644 index 0000000..4660348 --- /dev/null +++ b/configs/pvt/retinanet_pvt-s_fpn_1x_coco.py @@ -0,0 +1,6 @@ +_base_ = 'retinanet_pvt-t_fpn_1x_coco.py' +model = dict( + backbone=dict( + num_layers=[3, 4, 6, 3], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_small.pth'))) diff --git a/configs/pvt/retinanet_pvt-t_fpn_1x_coco.py b/configs/pvt/retinanet_pvt-t_fpn_1x_coco.py new file mode 100644 index 0000000..a6cff7d --- /dev/null +++ b/configs/pvt/retinanet_pvt-t_fpn_1x_coco.py @@ -0,0 +1,16 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='RetinaNet', + backbone=dict( + _delete_=True, + type='PyramidVisionTransformer', + num_layers=[2, 2, 2, 2], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_tiny.pth')), + neck=dict(in_channels=[64, 128, 320, 512])) +# optimizer +optimizer = dict(_delete_=True, type='AdamW', lr=0.0001, weight_decay=0.0001) diff --git a/configs/pvt/retinanet_pvtv2-b0_fpn_1x_coco.py b/configs/pvt/retinanet_pvtv2-b0_fpn_1x_coco.py new file mode 100644 index 0000000..cbe2295 --- /dev/null +++ b/configs/pvt/retinanet_pvtv2-b0_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + type='RetinaNet', + backbone=dict( + _delete_=True, + type='PyramidVisionTransformerV2', + embed_dims=32, + num_layers=[2, 2, 2, 2], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_v2_b0.pth')), + neck=dict(in_channels=[32, 64, 160, 256])) +# optimizer +optimizer = dict(_delete_=True, type='AdamW', lr=0.0001, weight_decay=0.0001) diff --git a/configs/pvt/retinanet_pvtv2-b1_fpn_1x_coco.py b/configs/pvt/retinanet_pvtv2-b1_fpn_1x_coco.py new file mode 100644 index 0000000..5374c50 --- /dev/null +++ b/configs/pvt/retinanet_pvtv2-b1_fpn_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = 'retinanet_pvtv2-b0_fpn_1x_coco.py' +model = dict( + backbone=dict( + embed_dims=64, + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_v2_b1.pth')), + neck=dict(in_channels=[64, 128, 320, 512])) diff --git a/configs/pvt/retinanet_pvtv2-b2_fpn_1x_coco.py b/configs/pvt/retinanet_pvtv2-b2_fpn_1x_coco.py new file mode 100644 index 0000000..cf9a18d --- /dev/null +++ b/configs/pvt/retinanet_pvtv2-b2_fpn_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = 'retinanet_pvtv2-b0_fpn_1x_coco.py' +model = dict( + backbone=dict( + embed_dims=64, + num_layers=[3, 4, 6, 3], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_v2_b2.pth')), + neck=dict(in_channels=[64, 128, 320, 512])) diff --git a/configs/pvt/retinanet_pvtv2-b3_fpn_1x_coco.py b/configs/pvt/retinanet_pvtv2-b3_fpn_1x_coco.py new file mode 100644 index 0000000..7a47f82 --- /dev/null +++ b/configs/pvt/retinanet_pvtv2-b3_fpn_1x_coco.py @@ -0,0 +1,8 @@ +_base_ = 'retinanet_pvtv2-b0_fpn_1x_coco.py' +model = dict( + backbone=dict( + embed_dims=64, + num_layers=[3, 4, 18, 3], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_v2_b3.pth')), + neck=dict(in_channels=[64, 128, 320, 512])) diff --git a/configs/pvt/retinanet_pvtv2-b4_fpn_1x_coco.py b/configs/pvt/retinanet_pvtv2-b4_fpn_1x_coco.py new file mode 100644 index 0000000..ec9103b --- /dev/null +++ b/configs/pvt/retinanet_pvtv2-b4_fpn_1x_coco.py @@ -0,0 +1,13 @@ +_base_ = 'retinanet_pvtv2-b0_fpn_1x_coco.py' +model = dict( + backbone=dict( + embed_dims=64, + num_layers=[3, 8, 27, 3], + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_v2_b4.pth')), + neck=dict(in_channels=[64, 128, 320, 512])) +# optimizer +optimizer = dict( + _delete_=True, type='AdamW', lr=0.0001 / 1.4, weight_decay=0.0001) +# dataset settings +data = dict(samples_per_gpu=1, workers_per_gpu=1) diff --git a/configs/pvt/retinanet_pvtv2-b5_fpn_1x_coco.py b/configs/pvt/retinanet_pvtv2-b5_fpn_1x_coco.py new file mode 100644 index 0000000..d8e6d23 --- /dev/null +++ b/configs/pvt/retinanet_pvtv2-b5_fpn_1x_coco.py @@ -0,0 +1,14 @@ +_base_ = 'retinanet_pvtv2-b0_fpn_1x_coco.py' +model = dict( + backbone=dict( + embed_dims=64, + num_layers=[3, 6, 40, 3], + mlp_ratios=(4, 4, 4, 4), + init_cfg=dict(checkpoint='https://github.com/whai362/PVT/' + 'releases/download/v2/pvt_v2_b5.pth')), + neck=dict(in_channels=[64, 128, 320, 512])) +# optimizer +optimizer = dict( + _delete_=True, type='AdamW', lr=0.0001 / 1.4, weight_decay=0.0001) +# dataset settings +data = dict(samples_per_gpu=1, workers_per_gpu=1) diff --git a/configs/queryinst/README.md b/configs/queryinst/README.md new file mode 100644 index 0000000..2051c5c --- /dev/null +++ b/configs/queryinst/README.md @@ -0,0 +1,26 @@ +# Instances as Queries + +## Introduction + + + +``` +@InProceedings{Fang_2021_ICCV, + author = {Fang, Yuxin and Yang, Shusheng and Wang, Xinggang and Li, Yu and Fang, Chen and Shan, Ying and Feng, Bin and Liu, Wenyu}, + title = {Instances As Queries}, + booktitle = {Proceedings of the IEEE/CVF International Conference on Computer Vision (ICCV)}, + month = {October}, + year = {2021}, + pages = {6910-6919} +} +``` + +## Results and Models + +| Model | Backbone | Style | Lr schd | Number of Proposals |Multi-Scale| RandomCrop | box AP | mask AP | Config | Download | +|:------------:|:---------:|:-------:|:-------:|:-------: |:-------: |:---------:|:------:|:------:|:------:|:--------:| +| QueryInst | R-50-FPN | pytorch | 1x | 100 | False | False | 42.0 | 37.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/queryinst/queryinst_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_1x_coco/queryinst_r50_fpn_1x_coco_20210907_084916-5a8f1998.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_1x_coco/queryinst_r50_fpn_1x_coco_20210907_084916.log.json) | +| QueryInst | R-50-FPN | pytorch | 3x | 100 | True | False | 44.8 | 39.8 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco/queryinst_r50_fpn_mstrain_480-800_3x_coco_20210901_103643-7837af86.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco/queryinst_r50_fpn_mstrain_480-800_3x_coco_20210901_103643.log.json) | +| QueryInst | R-50-FPN | pytorch | 3x | 300 | True | True | 47.5 | 41.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_101802-85cffbd8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_101802.log.json) | +| QueryInst | R-101-FPN | pytorch | 3x | 100 | True | False | 46.4 | 41.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco/queryinst_r101_fpn_mstrain_480-800_3x_coco_20210904_104048-91f9995b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco/queryinst_r101_fpn_mstrain_480-800_3x_coco_20210904_104048.log.json) | +| QueryInst | R-101-FPN | pytorch | 3x | 300 | True | True | 49.0 | 42.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_153621-76cce59f.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_153621.log.json) | diff --git a/configs/queryinst/metafile.yml b/configs/queryinst/metafile.yml new file mode 100644 index 0000000..da7f0a7 --- /dev/null +++ b/configs/queryinst/metafile.yml @@ -0,0 +1,100 @@ +Collections: + - Name: QueryInst + Metadata: + Training Data: COCO + Training Techniques: + - AdamW + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - FPN + - ResNet + - QueryInst + Paper: + URL: https://openaccess.thecvf.com/content/ICCV2021/papers/Fang_Instances_As_Queries_ICCV_2021_paper.pdf + Title: 'Instances as Queries' + README: configs/queryinst/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/master/mmdet/models/detectors/queryinst.py + Version: v2.18.0 + +Models: + - Name: queryinst_r50_fpn_1x_coco + In Collection: QueryInst + Config: configs/queryinst/queryinst_r50_fpn_1x_coco.py + Metadata: + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_1x_coco/queryinst_r50_fpn_1x_coco_20210907_084916-5a8f1998.pth + + - Name: queryinst_r50_fpn_mstrain_480-800_3x_coco + In Collection: QueryInst + Config: configs/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco.py + Metadata: + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco/queryinst_r50_fpn_mstrain_480-800_3x_coco_20210901_103643-7837af86.pth + + - Name: queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco + In Collection: QueryInst + Config: configs/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py + Metadata: + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 47.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 41.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_101802-85cffbd8.pth + + - Name: queryinst_r101_fpn_mstrain_480-800_3x_coco + In Collection: QueryInst + Config: configs/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco.py + Metadata: + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 46.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 41.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco/queryinst_r101_fpn_mstrain_480-800_3x_coco_20210904_104048-91f9995b.pth + + - Name: queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco + In Collection: QueryInst + Config: configs/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py + Metadata: + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 49.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 42.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_153621-76cce59f.pth diff --git a/configs/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py b/configs/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py new file mode 100644 index 0000000..fd138f5 --- /dev/null +++ b/configs/queryinst/queryinst_r101_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py @@ -0,0 +1,7 @@ +_base_ = './queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py' + +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco.py b/configs/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco.py new file mode 100644 index 0000000..07cae19 --- /dev/null +++ b/configs/queryinst/queryinst_r101_fpn_mstrain_480-800_3x_coco.py @@ -0,0 +1,7 @@ +_base_ = './queryinst_r50_fpn_mstrain_480-800_3x_coco.py' + +model = dict( + backbone=dict( + depth=101, + init_cfg=dict(type='Pretrained', + checkpoint='torchvision://resnet101'))) diff --git a/configs/queryinst/queryinst_r50_fpn_1x_coco.py b/configs/queryinst/queryinst_r50_fpn_1x_coco.py new file mode 100644 index 0000000..48f5773 --- /dev/null +++ b/configs/queryinst/queryinst_r50_fpn_1x_coco.py @@ -0,0 +1,138 @@ +_base_ = [ + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +num_stages = 6 +num_proposals = 100 +model = dict( + type='QueryInst', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=0, + add_extra_convs='on_input', + num_outs=4), + rpn_head=dict( + type='EmbeddingRPNHead', + num_proposals=num_proposals, + proposal_feature_channel=256), + roi_head=dict( + type='SparseRoIHead', + num_stages=num_stages, + stage_loss_weights=[1] * num_stages, + proposal_feature_channel=256, + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + mask_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=14, sampling_ratio=2), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=[ + dict( + type='DIIHead', + num_classes=80, + num_ffn_fcs=2, + num_heads=8, + num_cls_fcs=1, + num_reg_fcs=3, + feedforward_channels=2048, + in_channels=256, + dropout=0.0, + ffn_act_cfg=dict(type='ReLU', inplace=True), + dynamic_conv_cfg=dict( + type='DynamicConv', + in_channels=256, + feat_channels=64, + out_channels=256, + input_feat_shape=7, + act_cfg=dict(type='ReLU', inplace=True), + norm_cfg=dict(type='LN')), + loss_bbox=dict(type='L1Loss', loss_weight=5.0), + loss_iou=dict(type='GIoULoss', loss_weight=2.0), + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=2.0), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + clip_border=False, + target_means=[0., 0., 0., 0.], + target_stds=[0.5, 0.5, 1., 1.])) for _ in range(num_stages) + ], + mask_head=[ + dict( + type='DynamicMaskHead', + dynamic_conv_cfg=dict( + type='DynamicConv', + in_channels=256, + feat_channels=64, + out_channels=256, + input_feat_shape=14, + with_proj=False, + act_cfg=dict(type='ReLU', inplace=True), + norm_cfg=dict(type='LN')), + num_convs=4, + num_classes=80, + roi_feat_size=14, + in_channels=256, + conv_kernel_size=3, + conv_out_channels=256, + class_agnostic=False, + norm_cfg=dict(type='BN'), + upsample_cfg=dict(type='deconv', scale_factor=2), + loss_mask=dict( + type='DiceLoss', + loss_weight=8.0, + use_sigmoid=True, + activate=False, + eps=1e-5)) for _ in range(num_stages) + ]), + # training and testing settings + train_cfg=dict( + rpn=None, + rcnn=[ + dict( + assigner=dict( + type='HungarianAssigner', + cls_cost=dict(type='FocalLossCost', weight=2.0), + reg_cost=dict(type='BBoxL1Cost', weight=5.0), + iou_cost=dict(type='IoUCost', iou_mode='giou', + weight=2.0)), + sampler=dict(type='PseudoSampler'), + pos_weight=1, + mask_size=28, + ) for _ in range(num_stages) + ]), + test_cfg=dict( + rpn=None, rcnn=dict(max_per_img=num_proposals, mask_thr_binary=0.5))) + +# optimizer +optimizer = dict( + _delete_=True, + type='AdamW', + lr=0.0001, + weight_decay=0.0001, + paramwise_cfg=dict( + custom_keys={'backbone': dict(lr_mult=0.1, decay_mult=1.0)})) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=0.1, norm_type=2)) +# learning policy +lr_config = dict(policy='step', step=[8, 11], warmup_iters=1000) +runner = dict(type='EpochBasedRunner', max_epochs=12) diff --git a/configs/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py b/configs/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py new file mode 100644 index 0000000..3089b3c --- /dev/null +++ b/configs/queryinst/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco.py @@ -0,0 +1,54 @@ +_base_ = './queryinst_r50_fpn_mstrain_480-800_3x_coco.py' +num_proposals = 300 +model = dict( + rpn_head=dict(num_proposals=num_proposals), + test_cfg=dict( + _delete_=True, + rpn=None, + rcnn=dict(max_per_img=num_proposals, mask_thr_binary=0.5))) +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) + +# augmentation strategy originates from DETR. +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict( + type='AutoAugment', + policies=[[ + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), (576, 1333), + (608, 1333), (640, 1333), (672, 1333), (704, 1333), + (736, 1333), (768, 1333), (800, 1333)], + multiscale_mode='value', + keep_ratio=True) + ], + [ + dict( + type='Resize', + img_scale=[(400, 1333), (500, 1333), (600, 1333)], + multiscale_mode='value', + keep_ratio=True), + dict( + type='RandomCrop', + crop_type='absolute_range', + crop_size=(384, 600), + allow_negative_crop=True), + dict( + type='Resize', + img_scale=[(480, 1333), (512, 1333), (544, 1333), + (576, 1333), (608, 1333), (640, 1333), + (672, 1333), (704, 1333), (736, 1333), + (768, 1333), (800, 1333)], + multiscale_mode='value', + override=True, + keep_ratio=True) + ]]), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels', 'gt_masks']) +] +data = dict(train=dict(pipeline=train_pipeline)) diff --git a/configs/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco.py b/configs/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco.py new file mode 100644 index 0000000..89e2cd1 --- /dev/null +++ b/configs/queryinst/queryinst_r50_fpn_mstrain_480-800_3x_coco.py @@ -0,0 +1,23 @@ +_base_ = './queryinst_r50_fpn_1x_coco.py' + +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True) +min_values = (480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, value) for value in min_values], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']) +] + +data = dict(train=dict(pipeline=train_pipeline)) +lr_config = dict(policy='step', step=[27, 33]) +runner = dict(type='EpochBasedRunner', max_epochs=36) diff --git a/configs/regnet/README.md b/configs/regnet/README.md new file mode 100644 index 0000000..79ee258 --- /dev/null +++ b/configs/regnet/README.md @@ -0,0 +1,110 @@ +# Designing Network Design Spaces + +## Introduction + +[BACKBONE] + +We implement RegNetX and RegNetY models in detection systems and provide their first results on Mask R-CNN, Faster R-CNN and RetinaNet. + +The pre-trained modles are converted from [model zoo of pycls](https://github.com/facebookresearch/pycls/blob/master/MODEL_ZOO.md). + +```latex +@article{radosavovic2020designing, + title={Designing Network Design Spaces}, + author={Ilija Radosavovic and Raj Prateek Kosaraju and Ross Girshick and Kaiming He and Piotr Dollár}, + year={2020}, + eprint={2003.13678}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +## Usage + +To use a regnet model, there are two steps to do: + +1. Convert the model to ResNet-style supported by MMDetection +2. Modify backbone and neck in config accordingly + +### Convert model + +We already prepare models of FLOPs from 400M to 12G in our model zoo. + +For more general usage, we also provide script `regnet2mmdet.py` in the tools directory to convert the key of models pretrained by [pycls](https://github.com/facebookresearch/pycls/) to +ResNet-style checkpoints used in MMDetection. + +```bash +python -u tools/model_converters/regnet2mmdet.py ${PRETRAIN_PATH} ${STORE_PATH} +``` + +This script convert model from `PRETRAIN_PATH` and store the converted model in `STORE_PATH`. + +### Modify config + +The users can modify the config's `depth` of backbone and corresponding keys in `arch` according to the configs in the [pycls model zoo](https://github.com/facebookresearch/pycls/blob/master/MODEL_ZOO.md). +The parameter `in_channels` in FPN can be found in the Figure 15 & 16 of the paper (`wi` in the legend). +This directory already provides some configs with their performance, using RegNetX from 800MF to 12GF level. +For other pre-trained models or self-implemented regnet models, the users are responsible to check these parameters by themselves. + +**Note**: Although Fig. 15 & 16 also provide `w0`, `wa`, `wm`, `group_w`, and `bot_mul` for `arch`, they are quantized thus inaccurate, using them sometimes produces different backbone that does not match the key in the pre-trained model. + +## Results + +### Mask R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :---------: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +| [R-50-FPN](../mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py)| pytorch | 1x | 4.4 | 12.0 | 38.2 | 34.7 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_fpn_1x_coco/mask_rcnn_r50_fpn_1x_coco_20200205_050542.log.json) | +|[RegNetX-3.2GF-FPN](./mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py)| pytorch | 1x |5.0 ||40.3|36.6|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco/mask_rcnn_regnetx-3.2GF_fpn_1x_coco_20200520_163141-2a9d1814.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco/mask_rcnn_regnetx-3.2GF_fpn_1x_coco_20200520_163141.log.json) | +|[RegNetX-4.0GF-FPN](./mask_rcnn_regnetx-4GF_fpn_1x_coco.py)| pytorch | 1x |5.5||41.5|37.4|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco/mask_rcnn_regnetx-4GF_fpn_1x_coco_20200517_180217-32e9c92d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco/mask_rcnn_regnetx-4GF_fpn_1x_coco_20200517_180217.log.json) | +| [R-101-FPN](../mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py)| pytorch | 1x | 6.4 | 10.3 | 40.0 | 36.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_r101_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_1x_coco/mask_rcnn_r101_fpn_1x_coco_20200204-1efe0ed5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r101_fpn_1x_coco/mask_rcnn_r101_fpn_1x_coco_20200204_144809.log.json) | +|[RegNetX-6.4GF-FPN](./mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py)| pytorch | 1x |6.1 ||41.0|37.1|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco/mask_rcnn_regnetx-6.4GF_fpn_1x_coco_20200517_180439-3a7aae83.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco/mask_rcnn_regnetx-6.4GF_fpn_1x_coco_20200517_180439.log.json) | +| [X-101-32x4d-FPN](../mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py) | pytorch | 1x | 7.6 | 9.4 | 41.9 | 37.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco/mask_rcnn_x101_32x4d_fpn_1x_coco_20200205-478d0b67.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_x101_32x4d_fpn_1x_coco/mask_rcnn_x101_32x4d_fpn_1x_coco_20200205_034906.log.json) | +|[RegNetX-8.0GF-FPN](./mask_rcnn_regnetx-8GF_fpn_1x_coco.py)| pytorch | 1x |6.4 ||41.7|37.5|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco/mask_rcnn_regnetx-8GF_fpn_1x_coco_20200517_180515-09daa87e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco/mask_rcnn_regnetx-8GF_fpn_1x_coco_20200517_180515.log.json) | +|[RegNetX-12GF-FPN](./mask_rcnn_regnetx-12GF_fpn_1x_coco.py)| pytorch | 1x |7.4 ||42.2|38|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco/mask_rcnn_regnetx-12GF_fpn_1x_coco_20200517_180552-b538bd8b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco/mask_rcnn_regnetx-12GF_fpn_1x_coco_20200517_180552.log.json) | +|[RegNetX-3.2GF-FPN-DCN-C3-C5](./mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py)| pytorch | 1x |5.0 ||40.3|36.6|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco_20200520_172726-75f40794.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco_20200520_172726.log.json) | + +### Faster R-CNN + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :---------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| [R-50-FPN](../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py)| pytorch | 1x | 4.0 | 18.2 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130_204655.log.json) | +|[RegNetX-3.2GF-FPN](./faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py)| pytorch | 1x | 4.5||39.9|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco/faster_rcnn_regnetx-3.2GF_fpn_1x_coco_20200517_175927-126fd9bf.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco/faster_rcnn_regnetx-3.2GF_fpn_1x_coco_20200517_175927.log.json) | +|[RegNetX-3.2GF-FPN](./faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py)| pytorch | 2x | 4.5||41.1|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco/faster_rcnn_regnetx-3.2GF_fpn_2x_coco_20200520_223955-e2081918.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco/faster_rcnn_regnetx-3.2GF_fpn_2x_coco_20200520_223955.log.json) | + +### RetinaNet + +| Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +| :---------: | :-----: | :-----: | :------: | :------------: | :----: | :------: | :--------: | +| [R-50-FPN](../retinanet/retinanet_r50_fpn_1x_coco.py) | pytorch | 1x | 3.8 | 16.6 | 36.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/retinanet/retinanet_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130_002941.log.json) | +|[RegNetX-800MF-FPN](./retinanet_regnetx-800MF_fpn_1x_coco.py)| pytorch | 1x |2.5||35.6|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/retinanet_regnetx-800MF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-800MF_fpn_1x_coco/retinanet_regnetx-800MF_fpn_1x_coco_20200517_191403-f6f91d10.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-800MF_fpn_1x_coco/retinanet_regnetx-800MF_fpn_1x_coco_20200517_191403.log.json) | +|[RegNetX-1.6GF-FPN](./retinanet_regnetx-1.6GF_fpn_1x_coco.py)| pytorch | 1x |3.3||37.3|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco/retinanet_regnetx-1.6GF_fpn_1x_coco_20200517_191403-37009a9d.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco/retinanet_regnetx-1.6GF_fpn_1x_coco_20200517_191403.log.json) | +|[RegNetX-3.2GF-FPN](./retinanet_regnetx-3.2GF_fpn_1x_coco.py)| pytorch | 1x |4.2 ||39.1|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco/retinanet_regnetx-3.2GF_fpn_1x_coco_20200520_163141-cb1509e8.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco/retinanet_regnetx-3.2GF_fpn_1x_coco_20200520_163141.log.json) | + +### Pre-trained models + +We also train some models with longer schedules and multi-scale training. The users could finetune them for downstream tasks. + +| Method | Backbone | Style | Lr schd | Mem (GB) | Inf time (fps) | box AP | mask AP | Config | Download | +| :-----: | :-----: | :-----: | :-----: | :------: | :------------: | :----: | :-----: | :------: | :--------: | +|Faster RCNN |[RegNetX-400MF-FPN](./faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py)| pytorch | 3x |2.3 ||37.1|-|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco_20210526_095112-e1967c37.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco_20210526_095112.log.json) | +|Faster RCNN |[RegNetX-800MF-FPN](./faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py)| pytorch | 3x |2.8 ||38.8|-|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco_20210526_095118-a2c70b20.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco_20210526_095118.log.json) | +|Faster RCNN |[RegNetX-1.6GF-FPN](./faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py)| pytorch | 3x |3.4 ||40.5|-|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-1_20210526_095325-94aa46cc.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-1_20210526_095325.log.json) | +|Faster RCNN |[RegNetX-3.2GF-FPN](./faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py)| pytorch | 3x |4.4 ||42.3|-|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-3_20210526_095152-e16a5227.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-3_20210526_095152.log.json) | +|Faster RCNN |[RegNetX-4GF-FPN](./faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py)| pytorch | 3x |4.9 ||42.8|-|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco_20210526_095201-65eaf841.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco_20210526_095201.log.json) | +|Mask RCNN |[RegNetX-3.2GF-FPN](./mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py)| pytorch | 3x |5.0 ||43.1|38.7|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco_20200521_202221-99879813.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco_20200521_202221.log.json) | +|Mask RCNN |[RegNetX-400MF-FPN](./mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco.py)| pytorch | 3x |2.5 ||37.6|34.4|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco_20210601_235443-8aac57a4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco_20210601_235443.log.json) | +|Mask RCNN |[RegNetX-800MF-FPN](./mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco.py)| pytorch | 3x |2.9 ||39.5|36.1|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco_20210602_210641-715d51f5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco_20210602_210641.log.json) | +|Mask RCNN |[RegNetX-1.6GF-FPN](./mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco.py)| pytorch | 3x |3.6 ||40.9|37.5|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-1_20210602_210641-6764cff5.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-1_20210602_210641.log.json) | +|Mask RCNN |[RegNetX-3.2GF-FPN](./mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py) | pytorch | 3x |5.0 ||43.1|38.7|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco_20200521_202221-99879813.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco_20200521_202221.log.json) | +|Mask RCNN |[RegNetX-4GF-FPN](./mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco.py) | pytorch | 3x |5.1 ||43.4|39.2|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco_20210602_032621-00f0331c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco_20210602_032621.log.json) | +|Cascade Mask RCNN |[RegNetX-400MF-FPN](./cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py)| pytorch | 3x |4.3||41.6|36.4|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco_20210715_211619-5142f449.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco_20210715_211619.log.json) | +|Cascade Mask RCNN |[RegNetX-800MF-FPN](./cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py)| pytorch | 3x |4.8||42.8|37.6|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco_20210715_211616-dcbd13f4.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco_20210715_211616.log.json) | +|Cascade Mask RCNN |[RegNetX-1.6GF-FPN](./cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py)| pytorch | 3x |5.4||44.5|39.0|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-1_20210715_211616-75f29a61.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-1_20210715_211616.log.json) | +|Cascade Mask RCNN |[RegNetX-3.2GF-FPN](./cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py)| pytorch | 3x |6.4||45.8|40.0|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-3_20210715_211616-b9c2c58b.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-3_20210715_211616.log.json) | +|Cascade Mask RCNN |[RegNetX-4GF-FPN](./cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py) | pytorch | 3x |6.9||45.8|40.0|[config](https://github.com/open-mmlab/mmdetection/tree/master/configs/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco_20210715_212034-cbb1be4c.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco_20210715_212034.log.json) | + +### Notice + +1. The models are trained using a different weight decay, i.e., `weight_decay=5e-5` according to the setting in ImageNet training. This brings improvement of at least 0.7 AP absolute but does not improve the model using ResNet-50. +2. RetinaNets using RegNets are trained with learning rate 0.02 with gradient clip. We find that using learning rate 0.02 could improve the results by at least 0.7 AP absolute and gradient clip is necessary to stabilize the training. However, this does not improve the performance of ResNet-50-FPN RetinaNet. diff --git a/configs/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py b/configs/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..358d85a --- /dev/null +++ b/configs/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_1.6gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_1.6gf')), + neck=dict( + type='FPN', + in_channels=[72, 168, 408, 912], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py b/configs/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..8464571 --- /dev/null +++ b/configs/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,63 @@ +_base_ = [ + '../common/mstrain_3x_coco_instance.py', + '../_base_/models/cascade_mask_rcnn_r50_fpn.py' +] +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_3.2gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf')), + neck=dict( + type='FPN', + in_channels=[96, 192, 432, 1008], + out_channels=256, + num_outs=5)) +img_norm_cfg = dict( + # The mean and std are used in PyCls when training RegNets + mean=[103.53, 116.28, 123.675], + std=[57.375, 57.12, 58.395], + to_rgb=False) +train_pipeline = [ + # Images are converted to float32 directly after loading in PyCls + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) + +optimizer = dict(weight_decay=0.00005) diff --git a/configs/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py b/configs/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..2a8990a --- /dev/null +++ b/configs/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_400mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_400mf')), + neck=dict( + type='FPN', + in_channels=[32, 64, 160, 384], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py b/configs/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..3157863 --- /dev/null +++ b/configs/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_4.0gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_4.0gf')), + neck=dict( + type='FPN', + in_channels=[80, 240, 560, 1360], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py b/configs/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..41376ad --- /dev/null +++ b/configs/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_800mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_800mf')), + neck=dict( + type='FPN', + in_channels=[64, 128, 288, 672], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py b/configs/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..385b5ca --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_1.6gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_1.6gf')), + neck=dict( + type='FPN', + in_channels=[72, 168, 408, 912], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py b/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py new file mode 100644 index 0000000..88d270e --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py @@ -0,0 +1,57 @@ +_base_ = [ + '../_base_/models/faster_rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_3.2gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf')), + neck=dict( + type='FPN', + in_channels=[96, 192, 432, 1008], + out_channels=256, + num_outs=5)) +img_norm_cfg = dict( + # The mean and std are used in PyCls when training RegNets + mean=[103.53, 116.28, 123.675], + std=[57.375, 57.12, 58.395], + to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) diff --git a/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py b/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py new file mode 100644 index 0000000..612490b --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py @@ -0,0 +1,3 @@ +_base_ = './faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py' +lr_config = dict(step=[16, 22]) +runner = dict(type='EpochBasedRunner', max_epochs=24) diff --git a/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py b/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..b7e6e1a --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,61 @@ +_base_ = [ + '../common/mstrain_3x_coco.py', '../_base_/models/faster_rcnn_r50_fpn.py' +] +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_3.2gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf')), + neck=dict( + type='FPN', + in_channels=[96, 192, 432, 1008], + out_channels=256, + num_outs=5)) +img_norm_cfg = dict( + # The mean and std are used in PyCls when training RegNets + mean=[103.53, 116.28, 123.675], + std=[57.375, 57.12, 58.395], + to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 800)], + multiscale_mode='range', + keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(dataset=dict(pipeline=train_pipeline)), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) + +optimizer = dict(weight_decay=0.00005) diff --git a/configs/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py b/configs/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..0a05f6e --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_400mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_400mf')), + neck=dict( + type='FPN', + in_channels=[32, 64, 160, 384], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py b/configs/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..98b3fc2 --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_4.0gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_4.0gf')), + neck=dict( + type='FPN', + in_channels=[80, 240, 560, 1360], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py b/configs/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..67f448b --- /dev/null +++ b/configs/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py @@ -0,0 +1,17 @@ +_base_ = 'faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_800mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_800mf')), + neck=dict( + type='FPN', + in_channels=[64, 128, 288, 672], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco.py b/configs/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..7970c3c --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,26 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_1.6gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_1.6gf')), + neck=dict( + type='FPN', + in_channels=[72, 168, 408, 912], + out_channels=256, + num_outs=5)) + +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco.py b/configs/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco.py new file mode 100644 index 0000000..ce3661c --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = './mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_12gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_12gf')), + neck=dict( + type='FPN', + in_channels=[224, 448, 896, 2240], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py b/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py new file mode 100644 index 0000000..44bf0d1 --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py @@ -0,0 +1,58 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_3.2gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf')), + neck=dict( + type='FPN', + in_channels=[96, 192, 432, 1008], + out_channels=256, + num_outs=5)) +img_norm_cfg = dict( + # The mean and std are used in PyCls when training RegNets + mean=[103.53, 116.28, 123.675], + std=[57.375, 57.12, 58.395], + to_rgb=False) +train_pipeline = [ + # Images are converted to float32 directly after loading in PyCls + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) diff --git a/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py b/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py new file mode 100644 index 0000000..5b53428 --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py @@ -0,0 +1,7 @@ +_base_ = 'mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + dcn=dict(type='DCNv2', deform_groups=1, fallback_on_stride=False), + stage_with_dcn=(False, True, True, True), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf'))) diff --git a/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py b/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py new file mode 100644 index 0000000..aca64d3 --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py @@ -0,0 +1,66 @@ +_base_ = [ + '../_base_/models/mask_rcnn_r50_fpn.py', + '../_base_/datasets/coco_instance.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_3.2gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf')), + neck=dict( + type='FPN', + in_channels=[96, 192, 432, 1008], + out_channels=256, + num_outs=5)) +img_norm_cfg = dict( + # The mean and std are used in PyCls when training RegNets + mean=[103.53, 116.28, 123.675], + std=[57.375, 57.12, 58.395], + to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True, with_mask=True), + dict( + type='Resize', + img_scale=[(1333, 640), (1333, 672), (1333, 704), (1333, 736), + (1333, 768), (1333, 800)], + multiscale_mode='value', + keep_ratio=True), + 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', 'gt_masks']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) +lr_config = dict(step=[28, 34]) +runner = dict(type='EpochBasedRunner', max_epochs=36) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco.py b/configs/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..c38dfa6 --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,26 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_400mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_400mf')), + neck=dict( + type='FPN', + in_channels=[32, 64, 160, 384], + out_channels=256, + num_outs=5)) + +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco.py b/configs/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco.py new file mode 100644 index 0000000..874d485 --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = './mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_4.0gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_4.0gf')), + neck=dict( + type='FPN', + in_channels=[80, 240, 560, 1360], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco.py b/configs/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..f0b65ea --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,26 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_4.0gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_4.0gf')), + neck=dict( + type='FPN', + in_channels=[80, 240, 560, 1360], + out_channels=256, + num_outs=5)) + +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py b/configs/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py new file mode 100644 index 0000000..99387d8 --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = './mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_6.4gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_6.4gf')), + neck=dict( + type='FPN', + in_channels=[168, 392, 784, 1624], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco.py b/configs/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco.py new file mode 100644 index 0000000..335ebab --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco.py @@ -0,0 +1,26 @@ +_base_ = [ + '../common/mstrain-poly_3x_coco_instance.py', + '../_base_/models/mask_rcnn_r50_fpn.py' +] + +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_800mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_800mf')), + neck=dict( + type='FPN', + in_channels=[64, 128, 288, 672], + out_channels=256, + num_outs=5)) + +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco.py b/configs/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco.py new file mode 100644 index 0000000..1e7832f --- /dev/null +++ b/configs/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = './mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_8.0gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_8.0gf')), + neck=dict( + type='FPN', + in_channels=[80, 240, 720, 1920], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/metafile.yml b/configs/regnet/metafile.yml new file mode 100644 index 0000000..5390a35 --- /dev/null +++ b/configs/regnet/metafile.yml @@ -0,0 +1,437 @@ +Collections: + - Name: RegNet + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - RegNet + Paper: + URL: https://arxiv.org/abs/2003.13678 + Title: 'Designing Network Design Spaces' + README: configs/regnet/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.1.0/mmdet/models/backbones/regnet.py#L11 + Version: v2.1.0 + +Models: + - Name: mask_rcnn_regnetx-3.2GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.0 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_1x_coco/mask_rcnn_regnetx-3.2GF_fpn_1x_coco_20200520_163141-2a9d1814.pth + + - Name: mask_rcnn_regnetx-4GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 5.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-4GF_fpn_1x_coco/mask_rcnn_regnetx-4GF_fpn_1x_coco_20200517_180217-32e9c92d.pth + + - Name: mask_rcnn_regnetx-6.4GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.1 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.0 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-6.4GF_fpn_1x_coco/mask_rcnn_regnetx-6.4GF_fpn_1x_coco_20200517_180439-3a7aae83.pth + + - Name: mask_rcnn_regnetx-8GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 6.4 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.7 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-8GF_fpn_1x_coco/mask_rcnn_regnetx-8GF_fpn_1x_coco_20200517_180515-09daa87e.pth + + - Name: mask_rcnn_regnetx-12GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 7.4 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.2 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-12GF_fpn_1x_coco/mask_rcnn_regnetx-12GF_fpn_1x_coco_20200517_180552-b538bd8b.pth + + - Name: mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco.py + Metadata: + Training Memory (GB): 5.0 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco/mask_rcnn_regnetx-3.2GF_fpn_mdconv_c3-c5_1x_coco_20200520_172726-75f40794.pth + + - Name: faster_rcnn_regnetx-3.2GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_1x_coco/faster_rcnn_regnetx-3.2GF_fpn_1x_coco_20200517_175927-126fd9bf.pth + + - Name: faster_rcnn_regnetx-3.2GF_fpn_2x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco.py + Metadata: + Training Memory (GB): 4.5 + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_2x_coco/faster_rcnn_regnetx-3.2GF_fpn_2x_coco_20200520_223955-e2081918.pth + + - Name: retinanet_regnetx-800MF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/retinanet_regnetx-800MF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 2.5 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 35.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-800MF_fpn_1x_coco/retinanet_regnetx-800MF_fpn_1x_coco_20200517_191403-f6f91d10.pth + + - Name: retinanet_regnetx-1.6GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.3 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco/retinanet_regnetx-1.6GF_fpn_1x_coco_20200517_191403-37009a9d.pth + + - Name: retinanet_regnetx-3.2GF_fpn_1x_coco + In Collection: RegNet + Config: configs/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco.py + Metadata: + Training Memory (GB): 4.2 + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco/retinanet_regnetx-3.2GF_fpn_1x_coco_20200520_163141-cb1509e8.pth + + - Name: faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 2.3 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-400MF_fpn_mstrain_3x_coco_20210526_095112-e1967c37.pth + + - Name: faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 2.8 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-800MF_fpn_mstrain_3x_coco_20210526_095118-a2c70b20.pth + + - Name: faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 3.4 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-1_20210526_095325-94aa46cc.pth + + - Name: faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 4.4 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.3 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-3_20210526_095152-e16a5227.pth + + - Name: faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 4.9 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.8 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco/faster_rcnn_regnetx-4GF_fpn_mstrain_3x_coco_20210526_095201-65eaf841.pth + + - Name: mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.0 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco_20200521_202221-99879813.pth + + - Name: mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 2.5 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 34.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-400MF_fpn_mstrain-poly_3x_coco_20210601_235443-8aac57a4.pth + + - Name: mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco.py + Metadata: + Training Memory (GB): 2.9 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-800MF_fpn_mstrain-poly_3x_coco_20210602_210641-715d51f5.pth + + - Name: mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 3.6 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.9 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-1_20210602_210641-6764cff5.pth + + - Name: mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.0 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.1 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 38.7 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-1.6GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-1_20210602_210641-6e63e19c.pth + + - Name: mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.1 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 43.4 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco/mask_rcnn_regnetx-4GF_fpn_mstrain-poly_3x_coco_20210602_032621-00f0331c.pth + + - Name: cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 4.3 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.6 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 36.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-400MF_fpn_mstrain_3x_coco_20210715_211619-5142f449.pth + + - Name: cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 4.8 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 37.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-800MF_fpn_mstrain_3x_coco_20210715_211616-dcbd13f4.pth + + - Name: cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 5.4 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.5 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 39.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-1.6GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-1_20210715_211616-75f29a61.pth + + - Name: cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 6.4 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-3.2GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-3_20210715_211616-b9c2c58b.pth + + - Name: cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco + In Collection: RegNet + Config: configs/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco.py + Metadata: + Training Memory (GB): 6.9 + Epochs: 36 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 45.8 + - Task: Instance Segmentation + Dataset: COCO + Metrics: + mask AP: 40.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/regnet/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco/cascade_mask_rcnn_regnetx-4GF_fpn_mstrain_3x_coco_20210715_212034-cbb1be4c.pth diff --git a/configs/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco.py b/configs/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco.py new file mode 100644 index 0000000..7395c1b --- /dev/null +++ b/configs/regnet/retinanet_regnetx-1.6GF_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = './retinanet_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_1.6gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_1.6gf')), + neck=dict( + type='FPN', + in_channels=[72, 168, 408, 912], + out_channels=256, + num_outs=5)) diff --git a/configs/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco.py b/configs/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco.py new file mode 100644 index 0000000..f05307c --- /dev/null +++ b/configs/regnet/retinanet_regnetx-3.2GF_fpn_1x_coco.py @@ -0,0 +1,59 @@ +_base_ = [ + '../_base_/models/retinanet_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +model = dict( + backbone=dict( + _delete_=True, + type='RegNet', + arch='regnetx_3.2gf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_3.2gf')), + neck=dict( + type='FPN', + in_channels=[96, 192, 432, 1008], + out_channels=256, + num_outs=5)) +img_norm_cfg = dict( + # The mean and std are used in PyCls when training RegNets + mean=[103.53, 116.28, 123.675], + std=[57.375, 57.12, 58.395], + to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + 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=(1333, 800), + 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( + train=dict(pipeline=train_pipeline), + val=dict(pipeline=test_pipeline), + test=dict(pipeline=test_pipeline)) +optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.00005) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) diff --git a/configs/regnet/retinanet_regnetx-800MF_fpn_1x_coco.py b/configs/regnet/retinanet_regnetx-800MF_fpn_1x_coco.py new file mode 100644 index 0000000..f6f8989 --- /dev/null +++ b/configs/regnet/retinanet_regnetx-800MF_fpn_1x_coco.py @@ -0,0 +1,17 @@ +_base_ = './retinanet_regnetx-3.2GF_fpn_1x_coco.py' +model = dict( + backbone=dict( + type='RegNet', + arch='regnetx_800mf', + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch', + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://regnetx_800mf')), + neck=dict( + type='FPN', + in_channels=[64, 128, 288, 672], + out_channels=256, + num_outs=5)) diff --git a/configs/reppoints/README.md b/configs/reppoints/README.md new file mode 100644 index 0000000..fc58915 --- /dev/null +++ b/configs/reppoints/README.md @@ -0,0 +1,54 @@ +# RepPoints: Point Set Representation for Object Detection + +By [Ze Yang](https://yangze.tech/), [Shaohui Liu](http://b1ueber2y.me/), and [Han Hu](https://ancientmooner.github.io/). + +We provide code support and configuration files to reproduce the results in the paper for +["RepPoints: Point Set Representation for Object Detection"](https://arxiv.org/abs/1904.11490) on COCO object detection. + +## Introduction + + + +**RepPoints**, initially described in [arXiv](https://arxiv.org/abs/1904.11490), is a new representation method for visual objects, on which visual understanding tasks are typically centered. Visual object representation, aiming at both geometric description and appearance feature extraction, is conventionally achieved by `bounding box + RoIPool (RoIAlign)`. The bounding box representation is convenient to use; however, it provides only a rectangular localization of objects that lacks geometric precision and may consequently degrade feature quality. Our new representation, RepPoints, models objects by a `point set` instead of a `bounding box`, which learns to adaptively position themselves over an object in a manner that circumscribes the object’s `spatial extent` and enables `semantically aligned feature extraction`. This richer and more flexible representation maintains the convenience of bounding boxes while facilitating various visual understanding applications. This repo demonstrated the effectiveness of RepPoints for COCO object detection. + +Another feature of this repo is the demonstration of an `anchor-free detector`, which can be as effective as state-of-the-art anchor-based detection methods. The anchor-free detector can utilize either `bounding box` or `RepPoints` as the basic object representation. + +
+ +

Learning RepPoints in Object Detection.

+
+ +## Citing RepPoints + +``` +@inproceedings{yang2019reppoints, + title={RepPoints: Point Set Representation for Object Detection}, + author={Yang, Ze and Liu, Shaohui and Hu, Han and Wang, Liwei and Lin, Stephen}, + booktitle={The IEEE International Conference on Computer Vision (ICCV)}, + month={Oct}, + year={2019} +} +``` + +## Results and models + +The results on COCO 2017val are shown in the table below. + +| Method | Backbone | GN | Anchor | convert func | Lr schd | Mem (GB) | Inf time (fps) | box AP | Config | Download | +|:---------:|:-------------:|:---:|:------:|:------------:|:-------:|:--------:|:--------------:|:------:|:------:|:--------:| +| BBox | R-50-FPN | Y | single | - | 1x | 3.9 | 15.9 | 36.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/bbox_r50_grid_fpn_gn-neck+head_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/bbox_r50_grid_fpn_gn-neck%2Bhead_1x_coco/bbox_r50_grid_fpn_gn-neck%2Bhead_1x_coco_20200329-c98bfa96.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/bbox_r50_grid_fpn_gn-neck%2Bhead_1x_coco/bbox_r50_grid_fpn_gn-neck%2Bhead_1x_coco_20200329_145916.log.json) | +| BBox | R-50-FPN | Y | none | - | 1x | 3.9 | 15.4 | 37.4 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/bbox_r50_grid_center_fpn_gn-neck+Bhead_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/bbox_r50_grid_center_fpn_gn-neck%2Bhead_1x_coco/bbox_r50_grid_center_fpn_gn-neck%2Bhead_1x_coco_20200330-00f73d58.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/bbox_r50_grid_center_fpn_gn-neck%2Bhead_1x_coco/bbox_r50_grid_center_fpn_gn-neck%2Bhead_1x_coco_20200330_233609.log.json) | +| RepPoints | R-50-FPN | N | none | moment | 1x | 3.3 | 18.5 | 37.0 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/reppoints_moment_r50_fpn_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_1x_coco/reppoints_moment_r50_fpn_1x_coco_20200330-b73db8d1.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_1x_coco/reppoints_moment_r50_fpn_1x_coco_20200330_233609.log.json) | +| RepPoints | R-50-FPN | Y | none | moment | 1x | 3.9 | 17.5 | 38.1 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco_20200329-4b38409a.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco_20200329_145952.log.json) | +| RepPoints | R-50-FPN | Y | none | moment | 2x | 3.9 | - | 38.6 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/reppoints_moment_r50_fpn_gn-neck+head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco_20200329-91babaa2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco_20200329_150020.log.json) | +| RepPoints | R-101-FPN | Y | none | moment | 2x | 5.8 | 13.7 | 40.5 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/reppoints_moment_r101_fpn_gn-neck+head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r101_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r101_fpn_gn-neck%2Bhead_2x_coco_20200329-4fbc7310.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r101_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r101_fpn_gn-neck%2Bhead_2x_coco_20200329_132205.log.json) | +| RepPoints | R-101-FPN-DCN | Y | none | moment | 2x | 5.9 | 12.1 | 42.9 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-3309fbf2.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329_132134.log.json) | +| RepPoints | X-101-FPN-DCN | Y | none | moment | 2x | 7.1 | 9.3 | 44.2 | [config](https://github.com/open-mmlab/mmdetection/tree/master/configs/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py) | [model](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-f87da1ea.pth) | [log](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329_132201.log.json) | + +**Notes:** + +- `R-xx`, `X-xx` denote the ResNet and ResNeXt architectures, respectively. +- `DCN` denotes replacing 3x3 conv with the 3x3 deformable convolution in `c3-c5` stages of backbone. +- `none` in the `anchor` column means 2-d `center point` (x,y) is used to represent the initial object hypothesis. `single` denotes one 4-d anchor box (x,y,w,h) with IoU based label assign criterion is adopted. +- `moment`, `partial MinMax`, `MinMax` in the `convert func` column are three functions to convert a point set to a pseudo box. +- Note the results here are slightly different from those reported in the paper, due to framework change. While the original paper uses an [MXNet](https://mxnet.apache.org/) implementation, we re-implement the method in [PyTorch](https://pytorch.org/) based on mmdetection. diff --git a/configs/reppoints/bbox_r50_grid_center_fpn_gn-neck+head_1x_coco.py b/configs/reppoints/bbox_r50_grid_center_fpn_gn-neck+head_1x_coco.py new file mode 100644 index 0000000..b24c8db --- /dev/null +++ b/configs/reppoints/bbox_r50_grid_center_fpn_gn-neck+head_1x_coco.py @@ -0,0 +1,2 @@ +_base_ = './reppoints_moment_r50_fpn_gn-neck+head_1x_coco.py' +model = dict(bbox_head=dict(transform_method='minmax', use_grid_points=True)) diff --git a/configs/reppoints/bbox_r50_grid_fpn_gn-neck+head_1x_coco.py b/configs/reppoints/bbox_r50_grid_fpn_gn-neck+head_1x_coco.py new file mode 100644 index 0000000..8d5013d --- /dev/null +++ b/configs/reppoints/bbox_r50_grid_fpn_gn-neck+head_1x_coco.py @@ -0,0 +1,13 @@ +_base_ = './reppoints_moment_r50_fpn_gn-neck+head_1x_coco.py' +model = dict( + bbox_head=dict(transform_method='minmax', use_grid_points=True), + # training and testing settings + train_cfg=dict( + init=dict( + assigner=dict( + _delete_=True, + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0, + ignore_iof_thr=-1)))) diff --git a/configs/reppoints/metafile.yml b/configs/reppoints/metafile.yml new file mode 100644 index 0000000..cd4312c --- /dev/null +++ b/configs/reppoints/metafile.yml @@ -0,0 +1,181 @@ +Collections: + - Name: RepPoints + Metadata: + Training Data: COCO + Training Techniques: + - SGD with Momentum + - Weight Decay + Training Resources: 8x V100 GPUs + Architecture: + - Group Normalization + - FPN + - RepPoints + - ResNet + Paper: + URL: https://arxiv.org/abs/1904.11490 + Title: 'RepPoints: Point Set Representation for Object Detection' + README: configs/reppoints/README.md + Code: + URL: https://github.com/open-mmlab/mmdetection/blob/v2.0.0/mmdet/models/detectors/reppoints_detector.py#L9 + Version: v2.0.0 + +Models: + - Name: bbox_r50_grid_fpn_gn-neck+head_1x_coco + In Collection: RepPoints + Config: configs/reppoints/bbox_r50_grid_fpn_gn-neck+head_1x_coco.py + Metadata: + Training Memory (GB): 3.9 + inference time (ms/im): + - value: 62.89 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/bbox_r50_grid_fpn_gn-neck%2Bhead_1x_coco/bbox_r50_grid_fpn_gn-neck%2Bhead_1x_coco_20200329-c98bfa96.pth + + - Name: bbox_r50_grid_center_fpn_gn-neck+Bhead_1x_coco + In Collection: RepPoints + Config: configs/reppoints/bbox_r50_grid_center_fpn_gn-neck+Bhead_1x_coco.py + Metadata: + Training Memory (GB): 3.9 + inference time (ms/im): + - value: 64.94 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.4 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/bbox_r50_grid_center_fpn_gn-neck%2Bhead_1x_coco/bbox_r50_grid_center_fpn_gn-neck%2Bhead_1x_coco_20200330-00f73d58.pth + + - Name: reppoints_moment_r50_fpn_1x_coco + In Collection: RepPoints + Config: configs/reppoints/reppoints_moment_r50_fpn_1x_coco.py + Metadata: + Training Memory (GB): 3.3 + inference time (ms/im): + - value: 54.05 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.0 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_1x_coco/reppoints_moment_r50_fpn_1x_coco_20200330-b73db8d1.pth + + - Name: reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco + In Collection: RepPoints + Config: configs/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco.py + Metadata: + Training Memory (GB): 3.9 + inference time (ms/im): + - value: 57.14 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 12 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.1 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_1x_coco_20200329-4b38409a.pth + + - Name: reppoints_moment_r50_fpn_gn-neck+head_2x_coco + In Collection: RepPoints + Config: configs/reppoints/reppoints_moment_r50_fpn_gn-neck+head_2x_coco.py + Metadata: + Training Memory (GB): 3.9 + inference time (ms/im): + - value: 57.14 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.6 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco_20200329-91babaa2.pth + + - Name: reppoints_moment_r101_fpn_gn-neck+head_2x_coco + In Collection: RepPoints + Config: configs/reppoints/reppoints_moment_r101_fpn_gn-neck+head_2x_coco.py + Metadata: + Training Memory (GB): 5.8 + inference time (ms/im): + - value: 72.99 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.5 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r101_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r101_fpn_gn-neck%2Bhead_2x_coco_20200329-4fbc7310.pth + + - Name: reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck+head_2x_coco + In Collection: RepPoints + Config: configs/reppoints/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py + Metadata: + Training Memory (GB): 5.9 + inference time (ms/im): + - value: 82.64 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.9 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_r101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-3309fbf2.pth + + - Name: reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck+head_2x_coco + In Collection: RepPoints + Config: configs/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck+head_2x_coco.py + Metadata: + Training Memory (GB): 7.1 + inference time (ms/im): + - value: 107.53 + hardware: V100 + backend: PyTorch + batch size: 1 + mode: FP32 + resolution: (800, 1333) + Epochs: 24 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 44.2 + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-f87da1ea.pth diff --git a/configs/reppoints/reppoints.png b/configs/reppoints/reppoints.png new file mode 100644 index 0000000000000000000000000000000000000000..a9306d9ba6c659a670822213bf198099f9e125b1 GIT binary patch literal 1198109 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 z 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�nWL` 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�`0H_ga*!w>X;GW<6SbmUi^%T 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Π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

nL~cI`e#- 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