├── .gitignore ├── LICENSE ├── README.md ├── assets ├── teaser.png └── vis_bmp.png ├── environment.yml ├── mmcv ├── LICENSE ├── MANIFEST.in ├── README.rst ├── docs │ ├── Makefile │ ├── _static │ │ ├── flow_img2toimg1.png │ │ ├── flow_raw_images.png │ │ ├── flow_visualization.png │ │ ├── flow_warp.png │ │ ├── flow_warp_diff.png │ │ ├── parallel_progress.gif │ │ └── progress.gif │ ├── api.rst │ ├── cnn.md │ ├── conf.py │ ├── image.md │ ├── index.rst │ ├── io.md │ ├── make.bat │ ├── runner.md │ ├── utils.md │ ├── video.md │ └── visualization.md ├── examples │ ├── config_cifar10.py │ ├── dist_train_cifar10.sh │ ├── resnet_cifar.py │ └── train_cifar10.py ├── mmcv │ ├── __init__.py │ ├── arraymisc │ │ ├── __init__.py │ │ └── quantization.py │ ├── cnn │ │ ├── __init__.py │ │ ├── alexnet.py │ │ ├── resnet.py │ │ ├── vgg.py │ │ └── weight_init.py │ ├── fileio │ │ ├── __init__.py │ │ ├── handlers │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── json_handler.py │ │ │ ├── pickle_handler.py │ │ │ └── yaml_handler.py │ │ ├── io.py │ │ └── parse.py │ ├── image │ │ ├── __init__.py │ │ ├── io.py │ │ └── transforms │ │ │ ├── __init__.py │ │ │ ├── colorspace.py │ │ │ ├── geometry.py │ │ │ ├── normalize.py │ │ │ └── resize.py │ ├── opencv_info.py │ ├── parallel │ │ ├── __init__.py │ │ ├── _functions.py │ │ ├── collate.py │ │ ├── data_container.py │ │ ├── data_parallel.py │ │ ├── distributed.py │ │ └── scatter_gather.py │ ├── runner │ │ ├── __init__.py │ │ ├── checkpoint.py │ │ ├── hooks │ │ │ ├── __init__.py │ │ │ ├── checkpoint.py │ │ │ ├── closure.py │ │ │ ├── hook.py │ │ │ ├── iter_timer.py │ │ │ ├── logger │ │ │ │ ├── __init__.py │ │ │ │ ├── base.py │ │ │ │ ├── pavi.py │ │ │ │ ├── tensorboard.py │ │ │ │ └── text.py │ │ │ ├── lr_updater.py │ │ │ ├── memory.py │ │ │ ├── optimizer.py │ │ │ └── sampler_seed.py │ │ ├── log_buffer.py │ │ ├── parallel_test.py │ │ ├── priority.py │ │ ├── runner.py │ │ └── utils.py │ ├── utils │ │ ├── __init__.py │ │ ├── config.py │ │ ├── misc.py │ │ ├── path.py │ │ ├── progressbar.py │ │ └── timer.py │ ├── version.py │ ├── video │ │ ├── __init__.py │ │ ├── io.py │ │ ├── optflow.py │ │ ├── optflow_warp │ │ │ ├── __init__.py │ │ │ ├── flow_warp.cpp │ │ │ ├── flow_warp.hpp │ │ │ ├── flow_warp_module.cpp │ │ │ └── flow_warp_module.pyx │ │ └── processing.py │ └── visualization │ │ ├── __init__.py │ │ ├── color.py │ │ ├── image.py │ │ └── optflow.py ├── requirements.txt ├── setup.cfg ├── setup.py └── tests │ ├── test_arraymisc.py │ ├── test_config.py │ ├── test_fileio.py │ ├── test_image.py │ ├── test_misc.py │ ├── test_optflow.py │ ├── test_path.py │ ├── test_progressbar.py │ ├── test_runner.py │ ├── test_timer.py │ ├── test_video.py │ └── test_visualization.py ├── mmdetection ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── GETTING_STARTED.md ├── INSTALL.md ├── LICENSE ├── MODEL_ZOO.md ├── README.md ├── TECHNICAL_DETAILS.md ├── __init__.py ├── compile.sh ├── configs │ ├── __init__.py │ ├── bmp │ │ ├── finetune.py │ │ └── pretrain.py │ ├── dcn │ │ ├── README.md │ │ ├── cascade_mask_rcnn_dconv_c3-c5_r50_fpn_1x.py │ │ ├── cascade_rcnn_dconv_c3-c5_r50_fpn_1x.py │ │ ├── faster_rcnn_dconv_c3-c5_r50_fpn_1x.py │ │ ├── faster_rcnn_dconv_c3-c5_x101_32x4d_fpn_1x.py │ │ ├── faster_rcnn_dpool_r50_fpn_1x.py │ │ ├── faster_rcnn_mdconv_c3-c5_r50_fpn_1x.py │ │ ├── faster_rcnn_mdpool_r50_fpn_1x.py │ │ └── mask_rcnn_dconv_c3-c5_r50_fpn_1x.py │ ├── empirical_attention │ │ ├── README.md │ │ ├── faster_rcnn_r50_fpn_attention_0010_1x.py │ │ ├── faster_rcnn_r50_fpn_attention_0010_dcn_1x.py │ │ ├── faster_rcnn_r50_fpn_attention_1111_1x.py │ │ └── faster_rcnn_r50_fpn_attention_1111_dcn_1x.py │ ├── fcos │ │ ├── README.md │ │ ├── fcos_mstrain_640_800_r101_caffe_fpn_gn_2x_4gpu.py │ │ ├── fcos_mstrain_640_800_x101_64x4d_fpn_gn_2x.py │ │ └── fcos_r50_caffe_fpn_gn_1x_4gpu.py │ ├── fp16 │ │ ├── faster_rcnn_r50_fpn_fp16_1x.py │ │ ├── mask_rcnn_r50_fpn_fp16_1x.py │ │ └── retinanet_r50_fpn_fp16_1x.py │ ├── gcnet │ │ ├── README.md │ │ ├── mask_rcnn_r16_gcb_c3-c5_r50_fpn_1x.py │ │ ├── mask_rcnn_r16_gcb_c3-c5_r50_fpn_syncbn_1x.py │ │ ├── mask_rcnn_r4_gcb_c3-c5_r50_fpn_1x.py │ │ ├── mask_rcnn_r4_gcb_c3-c5_r50_fpn_syncbn_1x.py │ │ └── mask_rcnn_r50_fpn_sbn_1x.py │ ├── ghm │ │ ├── README.md │ │ └── retinanet_ghm_r50_fpn_1x.py │ ├── gn+ws │ │ ├── README.md │ │ ├── faster_rcnn_r50_fpn_gn_ws_1x.py │ │ ├── mask_rcnn_r50_fpn_gn_ws_20_23_24e.py │ │ ├── mask_rcnn_r50_fpn_gn_ws_2x.py │ │ └── mask_rcnn_x101_32x4d_fpn_gn_ws_2x.py │ ├── gn │ │ ├── README.md │ │ ├── mask_rcnn_r101_fpn_gn_2x.py │ │ ├── mask_rcnn_r50_fpn_gn_2x.py │ │ └── mask_rcnn_r50_fpn_gn_contrib_2x.py │ ├── grid_rcnn │ │ ├── README.md │ │ ├── grid_rcnn_gn_head_r50_fpn_2x.py │ │ └── grid_rcnn_gn_head_x101_32x4d_fpn_2x.py │ ├── guided_anchoring │ │ ├── README.md │ │ ├── ga_fast_r50_caffe_fpn_1x.py │ │ ├── ga_faster_r50_caffe_fpn_1x.py │ │ ├── ga_faster_x101_32x4d_fpn_1x.py │ │ ├── ga_retinanet_r50_caffe_fpn_1x.py │ │ ├── ga_retinanet_x101_32x4d_fpn_1x.py │ │ ├── ga_rpn_r101_caffe_rpn_1x.py │ │ ├── ga_rpn_r50_caffe_fpn_1x.py │ │ └── ga_rpn_x101_32x4d_fpn_1x.py │ ├── hrnet │ │ ├── README.md │ │ ├── cascade_rcnn_hrnetv2p_w32_20e.py │ │ ├── faster_rcnn_hrnetv2p_w18_1x.py │ │ ├── faster_rcnn_hrnetv2p_w32_1x.py │ │ ├── faster_rcnn_hrnetv2p_w40_1x.py │ │ ├── mask_rcnn_hrnetv2p_w18_1x.py │ │ └── mask_rcnn_hrnetv2p_w32_1x.py │ ├── htc │ │ ├── README.md │ │ ├── htc_dconv_c3-c5_mstrain_400_1400_x101_64x4d_fpn_20e.py │ │ ├── htc_r101_fpn_20e.py │ │ ├── htc_r50_fpn_1x.py │ │ ├── htc_r50_fpn_20e.py │ │ ├── htc_without_semantic_r50_fpn_1x.py │ │ ├── htc_x101_32x4d_fpn_20e_16gpu.py │ │ └── htc_x101_64x4d_fpn_20e_16gpu.py │ ├── libra_rcnn │ │ ├── README.md │ │ ├── libra_fast_rcnn_r50_fpn_1x.py │ │ ├── libra_faster_rcnn_r101_fpn_1x.py │ │ ├── libra_faster_rcnn_r50_fpn_1x.py │ │ ├── libra_faster_rcnn_x101_64x4d_fpn_1x.py │ │ └── libra_retinanet_r50_fpn_1x.py │ ├── ms_rcnn │ │ ├── README.md │ │ ├── ms_rcnn_r101_caffe_fpn_1x.py │ │ ├── ms_rcnn_r50_caffe_fpn_1x.py │ │ └── ms_rcnn_x101_64x4d_fpn_1x.py │ ├── pascal_voc │ │ ├── faster_rcnn_r50_fpn_1x_voc0712.py │ │ ├── ssd300_voc.py │ │ └── ssd512_voc.py │ ├── scratch │ │ ├── README.md │ │ ├── scratch_faster_rcnn_r50_fpn_gn_6x.py │ │ └── scratch_mask_rcnn_r50_fpn_gn_6x.py │ └── wider_face │ │ ├── README.md │ │ └── ssd300_wider_face.py ├── data │ └── .gitignore ├── demo_images │ └── 001289747.jpg ├── mmdet │ ├── __init__.py │ ├── apis │ │ ├── __init__.py │ │ ├── adv_runner.py │ │ ├── env.py │ │ ├── inference.py │ │ └── train.py │ ├── core │ │ ├── __init__.py │ │ ├── anchor │ │ │ ├── __init__.py │ │ │ ├── anchor_generator.py │ │ │ ├── anchor_target.py │ │ │ └── guided_anchor_target.py │ │ ├── bbox │ │ │ ├── __init__.py │ │ │ ├── assign_sampling.py │ │ │ ├── assigners │ │ │ │ ├── __init__.py │ │ │ │ ├── approx_max_iou_assigner.py │ │ │ │ ├── assign_result.py │ │ │ │ ├── base_assigner.py │ │ │ │ └── max_iou_assigner.py │ │ │ ├── bbox_target.py │ │ │ ├── geometry.py │ │ │ ├── samplers │ │ │ │ ├── __init__.py │ │ │ │ ├── base_sampler.py │ │ │ │ ├── combined_sampler.py │ │ │ │ ├── instance_balanced_pos_sampler.py │ │ │ │ ├── iou_balanced_neg_sampler.py │ │ │ │ ├── ohem_sampler.py │ │ │ │ ├── pseudo_sampler.py │ │ │ │ ├── random_sampler.py │ │ │ │ └── sampling_result.py │ │ │ └── transforms.py │ │ ├── evaluation │ │ │ ├── __init__.py │ │ │ ├── bbox_overlaps.py │ │ │ ├── class_names.py │ │ │ ├── coco_utils.py │ │ │ ├── eval_hooks.py │ │ │ ├── mean_ap.py │ │ │ └── recall.py │ │ ├── fp16 │ │ │ ├── __init__.py │ │ │ ├── decorators.py │ │ │ ├── hooks.py │ │ │ └── utils.py │ │ ├── mask │ │ │ ├── __init__.py │ │ │ ├── mask_target.py │ │ │ └── utils.py │ │ ├── post_processing │ │ │ ├── __init__.py │ │ │ ├── bbox_nms.py │ │ │ └── merge_augs.py │ │ └── utils │ │ │ ├── __init__.py │ │ │ ├── adv_checkpoint.py │ │ │ ├── adv_optimizer.py │ │ │ ├── avg_meter.py │ │ │ ├── dist_utils.py │ │ │ ├── eval_utils.py │ │ │ ├── lr_hooks.py │ │ │ ├── misc.py │ │ │ ├── radam.py │ │ │ └── smpl_tensorboard.py │ ├── datasets │ │ ├── __init__.py │ │ ├── coco.py │ │ ├── coco_kpts.py │ │ ├── common.py │ │ ├── concat_dataset.py │ │ ├── custom.py │ │ ├── extra_aug.py │ │ ├── h36m.py │ │ ├── loader │ │ │ ├── __init__.py │ │ │ ├── build_loader.py │ │ │ └── sampler.py │ │ ├── repeat_dataset.py │ │ ├── transforms.py │ │ ├── utils.py │ │ ├── voc.py │ │ ├── wider_face.py │ │ └── xml_style.py │ ├── models │ │ ├── __init__.py │ │ ├── anchor_heads │ │ │ ├── __init__.py │ │ │ ├── anchor_head.py │ │ │ ├── fcos_head.py │ │ │ ├── ga_retina_head.py │ │ │ ├── ga_rpn_head.py │ │ │ ├── guided_anchor_head.py │ │ │ ├── retina_head.py │ │ │ ├── rpn_head.py │ │ │ └── ssd_head.py │ │ ├── backbones │ │ │ ├── __init__.py │ │ │ ├── hrnet.py │ │ │ ├── resnet.py │ │ │ ├── resnext.py │ │ │ └── ssd_vgg.py │ │ ├── bbox_heads │ │ │ ├── __init__.py │ │ │ ├── bbox_head.py │ │ │ └── convfc_bbox_head.py │ │ ├── builder.py │ │ ├── detectors │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── bmp.py │ │ │ ├── cascade_rcnn.py │ │ │ ├── fast_rcnn.py │ │ │ ├── faster_rcnn.py │ │ │ ├── fcos.py │ │ │ ├── grid_rcnn.py │ │ │ ├── htc.py │ │ │ ├── mask_rcnn.py │ │ │ ├── mask_scoring_rcnn.py │ │ │ ├── retinanet.py │ │ │ ├── rpn.py │ │ │ ├── single_stage.py │ │ │ ├── smpl_rcnn.py │ │ │ ├── test_mixins.py │ │ │ └── two_stage.py │ │ ├── losses │ │ │ ├── __init__.py │ │ │ ├── accuracy.py │ │ │ ├── balanced_l1_loss.py │ │ │ ├── bmp_loss.py │ │ │ ├── cross_entropy_loss.py │ │ │ ├── focal_loss.py │ │ │ ├── ghm_loss.py │ │ │ ├── iou_loss.py │ │ │ ├── mse_loss.py │ │ │ ├── smooth_l1_loss.py │ │ │ └── utils.py │ │ ├── mask_heads │ │ │ ├── __init__.py │ │ │ ├── fcn_kpts_head.py │ │ │ ├── fcn_mask_head.py │ │ │ ├── fused_semantic_head.py │ │ │ ├── grid_head.py │ │ │ ├── htc_mask_head.py │ │ │ └── maskiou_head.py │ │ ├── necks │ │ │ ├── __init__.py │ │ │ ├── bfp.py │ │ │ ├── fpn.py │ │ │ └── hrfpn.py │ │ ├── plugins │ │ │ ├── __init__.py │ │ │ ├── generalized_attention.py │ │ │ └── non_local.py │ │ ├── registry.py │ │ ├── roi_extractors │ │ │ ├── __init__.py │ │ │ └── single_level.py │ │ ├── shared_heads │ │ │ ├── __init__.py │ │ │ └── res_layer.py │ │ ├── smpl_heads │ │ │ ├── __init__.py │ │ │ ├── bmp_head.py │ │ │ └── smpl_common.py │ │ └── utils │ │ │ ├── __init__.py │ │ │ ├── camera.py │ │ │ ├── conv_module.py │ │ │ ├── conv_ws.py │ │ │ ├── kpts.py │ │ │ ├── norm.py │ │ │ ├── panutils.py │ │ │ ├── pose_utils.py │ │ │ ├── scale.py │ │ │ ├── smpl │ │ │ ├── __init__.py │ │ │ ├── renderer.py │ │ │ ├── smpl.py │ │ │ └── viz.py │ │ │ ├── smpl_utils.py │ │ │ └── weight_init.py │ ├── ops │ │ ├── __init__.py │ │ ├── dcn │ │ │ ├── __init__.py │ │ │ ├── functions │ │ │ │ ├── __init__.py │ │ │ │ ├── deform_conv.py │ │ │ │ └── deform_pool.py │ │ │ ├── modules │ │ │ │ ├── __init__.py │ │ │ │ ├── deform_conv.py │ │ │ │ └── deform_pool.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ │ ├── deform_conv_cuda.cpp │ │ │ │ ├── deform_conv_cuda_kernel.cu │ │ │ │ ├── deform_pool_cuda.cpp │ │ │ │ └── deform_pool_cuda_kernel.cu │ │ ├── gcb │ │ │ ├── __init__.py │ │ │ └── context_block.py │ │ ├── kpts_nms │ │ │ ├── __init__.py │ │ │ ├── nms_wrapper.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ │ ├── kpts_nms_cpu.cpp │ │ │ │ ├── kpts_nms_cuda.cpp │ │ │ │ └── kpts_nms_kernel.cu │ │ ├── masked_conv │ │ │ ├── __init__.py │ │ │ ├── functions │ │ │ │ ├── __init__.py │ │ │ │ └── masked_conv.py │ │ │ ├── modules │ │ │ │ ├── __init__.py │ │ │ │ └── masked_conv.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ │ ├── masked_conv2d_cuda.cpp │ │ │ │ └── masked_conv2d_kernel.cu │ │ ├── nms │ │ │ ├── __init__.py │ │ │ ├── nms_wrapper.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ │ ├── nms_cpu.cpp │ │ │ │ ├── nms_cuda.cpp │ │ │ │ ├── nms_kernel.cu │ │ │ │ ├── soft_nms_cpu.cpp │ │ │ │ └── soft_nms_cpu.pyx │ │ ├── roi_align │ │ │ ├── __init__.py │ │ │ ├── functions │ │ │ │ ├── __init__.py │ │ │ │ └── roi_align.py │ │ │ ├── gradcheck.py │ │ │ ├── modules │ │ │ │ ├── __init__.py │ │ │ │ └── roi_align.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ │ ├── roi_align_cuda.cpp │ │ │ │ └── roi_align_kernel.cu │ │ ├── roi_pool │ │ │ ├── __init__.py │ │ │ ├── functions │ │ │ │ ├── __init__.py │ │ │ │ └── roi_pool.py │ │ │ ├── gradcheck.py │ │ │ ├── modules │ │ │ │ ├── __init__.py │ │ │ │ └── roi_pool.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ │ ├── roi_pool_cuda.cpp │ │ │ │ └── roi_pool_kernel.cu │ │ └── sigmoid_focal_loss │ │ │ ├── __init__.py │ │ │ ├── functions │ │ │ ├── __init__.py │ │ │ └── sigmoid_focal_loss.py │ │ │ ├── modules │ │ │ ├── __init__.py │ │ │ └── sigmoid_focal_loss.py │ │ │ ├── setup.py │ │ │ └── src │ │ │ ├── sigmoid_focal_loss.cpp │ │ │ └── sigmoid_focal_loss_cuda.cu │ └── version.py ├── scripts │ ├── demo.sh │ ├── eval_all.sh │ ├── eval_haggling.sh │ ├── eval_mafia.sh │ ├── eval_mupots.sh │ ├── eval_pizza.sh │ ├── eval_pw3d.sh │ ├── eval_ultimatum.sh │ ├── finetune.sh │ └── pretrain.sh ├── setup.py └── tools │ ├── demo.py │ ├── eval_all.py │ ├── full_eval.py │ └── train.py ├── neural_renderer ├── LICENSE ├── README.md ├── examples │ ├── example1.py │ ├── example2.py │ ├── example3.py │ └── example4.py ├── neural_renderer │ ├── __init__.py │ ├── cuda │ │ ├── __init__.py │ │ ├── create_texture_image_cuda.cpp │ │ ├── create_texture_image_cuda_kernel.cu │ │ ├── load_textures_cuda.cpp │ │ ├── load_textures_cuda_kernel.cu │ │ ├── rasterize_cuda.cpp │ │ └── rasterize_cuda_kernel.cu │ ├── get_points_from_angles.py │ ├── lighting.py │ ├── load_obj.py │ ├── look.py │ ├── look_at.py │ ├── mesh.py │ ├── perspective.py │ ├── projection.py │ ├── rasterize.py │ ├── renderer.py │ ├── save_obj.py │ ├── vertices_to_faces.py │ └── visibility.py ├── setup.py └── tests │ ├── test_get_points_from_angles.py │ ├── test_lighting.py │ ├── test_load_obj.py │ ├── test_look.py │ ├── test_look_at.py │ ├── test_perspective.py │ ├── test_rasterize.py │ ├── test_rasterize_depth.py │ ├── test_rasterize_silhouettes.py │ ├── test_renderer.py │ ├── test_save_obj.py │ ├── test_vertices_to_faces.py │ ├── testn.png │ └── utils.py ├── preprocess_datasets ├── full │ ├── README.md │ ├── muco.py │ ├── pw3d.py │ └── utils.py └── pretrain │ ├── coco.py │ ├── h36m.py │ ├── lsp.py │ ├── lspet.py │ ├── mpi_inf_3dhp.py │ ├── mpii.py │ ├── process_data.py │ └── utils.py └── sdf ├── README.md ├── sdf ├── __init__.py ├── collisionvolume.py ├── csrc │ ├── sdf_cuda.cpp │ └── sdf_cuda_kernel.cu ├── sdf.py └── sdf_loss.py └── setup.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Pyjcsx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/teaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/assets/teaser.png -------------------------------------------------------------------------------- /assets/vis_bmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/assets/vis_bmp.png -------------------------------------------------------------------------------- /mmcv/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include mmcv/video/optflow_warp/*.hpp -------------------------------------------------------------------------------- /mmcv/README.rst: -------------------------------------------------------------------------------- 1 | MMCV 2 | ==== 3 | 4 | .. image:: https://travis-ci.com/open-mmlab/mmcv.svg?branch=master 5 | :target: https://travis-ci.com/open-mmlab/mmcv 6 | 7 | .. image:: https://codecov.io/gh/open-mmlab/mmcv/branch/master/graph/badge.svg 8 | :target: https://codecov.io/gh/open-mmlab/mmcv 9 | 10 | .. image:: https://img.shields.io/github/license/open-mmlab/mmcv.svg 11 | :target: https://github.com/open-mmlab/mmcv/blob/master/LICENSE 12 | 13 | 14 | Introduction 15 | ------------ 16 | 17 | MMCV is a foundational python library for computer vision research and supports many 18 | research projects in MMLAB, such as `MMDetection `_ 19 | and `MMAction `_. 20 | 21 | It provides the following functionalities. 22 | 23 | - Universal IO APIs 24 | - Image processing 25 | - Video processing 26 | - Image and annotation visualization 27 | - Useful utilities (progress bar, timer, ...) 28 | - PyTorch runner with hooking mechanism 29 | - Various CNN architectures 30 | 31 | See the `documentation `_ for more features and usage. 32 | 33 | 34 | Installation 35 | ------------ 36 | 37 | Try and start with 38 | 39 | .. code:: 40 | 41 | pip install mmcv 42 | 43 | 44 | or install from source 45 | 46 | .. code:: 47 | 48 | git clone https://github.com/open-mmlab/mmcv.git 49 | cd mmcv 50 | pip install . # (add "-e" if you want to develop or modify the codes) 51 | -------------------------------------------------------------------------------- /mmcv/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /mmcv/docs/_static/flow_img2toimg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/flow_img2toimg1.png -------------------------------------------------------------------------------- /mmcv/docs/_static/flow_raw_images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/flow_raw_images.png -------------------------------------------------------------------------------- /mmcv/docs/_static/flow_visualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/flow_visualization.png -------------------------------------------------------------------------------- /mmcv/docs/_static/flow_warp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/flow_warp.png -------------------------------------------------------------------------------- /mmcv/docs/_static/flow_warp_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/flow_warp_diff.png -------------------------------------------------------------------------------- /mmcv/docs/_static/parallel_progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/parallel_progress.gif -------------------------------------------------------------------------------- /mmcv/docs/_static/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/docs/_static/progress.gif -------------------------------------------------------------------------------- /mmcv/docs/api.rst: -------------------------------------------------------------------------------- 1 | API 2 | ==== 3 | 4 | 5 | fileio 6 | -------------- 7 | .. automodule:: mmcv.fileio 8 | :members: 9 | 10 | image 11 | -------------- 12 | .. automodule:: mmcv.image 13 | :members: 14 | 15 | video 16 | -------------- 17 | .. automodule:: mmcv.video 18 | :members: 19 | 20 | arraymisc 21 | -------------- 22 | .. automodule:: mmcv.arraymisc 23 | :members: 24 | 25 | visualization 26 | -------------- 27 | .. automodule:: mmcv.visualization 28 | :members: 29 | 30 | utils 31 | -------------- 32 | .. automodule:: mmcv.utils 33 | :members: 34 | 35 | runner 36 | -------------- 37 | .. automodule:: mmcv.runner 38 | :members: 39 | -------------------------------------------------------------------------------- /mmcv/docs/cnn.md: -------------------------------------------------------------------------------- 1 | ## CNN 2 | 3 | The subpackage `mmcv.cnn` ships with lots of CNN backbones and the number is growing. 4 | Different from models provided in `torchvision`, these models are designed 5 | for actual usage in different cases, with highly customizable interfaces. 6 | 7 | Taking ResNet as an example, you can specify the following things: 8 | 9 | - number of stages 10 | - stage of output feature maps 11 | - location of the stride 2 convolutional layer 12 | - strides and dilation of each stage 13 | - whether to freeze some first stages 14 | - whether to fix BN stats 15 | - whether to fix BN parameters 16 | - whether to use checkpoint to save memory 17 | -------------------------------------------------------------------------------- /mmcv/docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | Contents 4 | ======== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | io.md 10 | image.md 11 | video.md 12 | visualization.md 13 | utils.md 14 | runner.md 15 | cnn.md 16 | api.rst 17 | 18 | 19 | 20 | Indices and tables 21 | ================== 22 | 23 | * :ref:`genindex` 24 | * :ref:`search` 25 | -------------------------------------------------------------------------------- /mmcv/docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /mmcv/docs/runner.md: -------------------------------------------------------------------------------- 1 | ## Runner 2 | 3 | The runner module aims to help users to start training with less code, while stays 4 | flexible and configurable. 5 | 6 | Documentation and examples are still on going. -------------------------------------------------------------------------------- /mmcv/docs/utils.md: -------------------------------------------------------------------------------- 1 | ## Utils 2 | 3 | ### Config 4 | 5 | `Config` class is used for manipulating config and config files. It supports 6 | loading configs from multiple file formats including **python**, **json** and **yaml**. 7 | It provides dict-like apis to get and set values. 8 | 9 | Here is an example of the config file `test.py`. 10 | 11 | ```python 12 | a = 1 13 | b = {'b1': [0, 1, 2], 'b2': None} 14 | c = (1, 2) 15 | d = 'string' 16 | ``` 17 | 18 | To load and use configs 19 | 20 | ```python 21 | cfg = Config.fromfile('test.py') 22 | assert cfg.a == 1 23 | assert cfg.b.b1 == [0, 1, 2] 24 | cfg.c = None 25 | assert cfg.c == None 26 | ``` 27 | 28 | ### ProgressBar 29 | 30 | If you want to apply a method to a list of items and track the progress, `track_progress` 31 | is a good choice. It will display a progress bar to tell the progress and ETA. 32 | 33 | ```python 34 | import mmcv 35 | 36 | def func(item): 37 | # do something 38 | pass 39 | 40 | tasks = [item_1, item_2, ..., item_n] 41 | 42 | mmcv.track_progress(func, tasks) 43 | ``` 44 | 45 | The output is like the following. 46 | ![progress](_static/progress.gif) 47 | 48 | There is another method `track_parallel_progress`, which wraps multiprocessing and 49 | progress visualization. 50 | 51 | ```python 52 | mmcv.track_parallel_progress(func, tasks, 8) # 8 workers 53 | ``` 54 | 55 | ![progress](_static/parallel_progress.gif) 56 | 57 | 58 | ### Timer 59 | 60 | It is convinient to compute the runtime of a code block with `Timer`. 61 | 62 | ```python 63 | import time 64 | 65 | with mmcv.Timer(): 66 | # simulate some code block 67 | time.sleep(1) 68 | ``` 69 | 70 | or try with `since_start()` and `since_last_check()`. This former can 71 | return the runtime since the timer starts and the latter will return the time 72 | since the last time checked. 73 | 74 | ```python 75 | timer = mmcv.Timer() 76 | # code block 1 here 77 | print(timer.since_start()) 78 | # code block 2 here 79 | print(timer.since_last_check()) 80 | print(timer.since_start()) 81 | ``` 82 | -------------------------------------------------------------------------------- /mmcv/docs/visualization.md: -------------------------------------------------------------------------------- 1 | ## Visualization 2 | 3 | `mmcv` can show images and annotations (currently supported types include bounding boxes). 4 | 5 | ```python 6 | # show an image file 7 | mmcv.imshow('a.jpg') 8 | 9 | # show a loaded image 10 | img = np.random.rand(100, 100, 3) 11 | mmcv.imshow(img) 12 | 13 | # show image with bounding boxes 14 | img = np.random.rand(100, 100, 3) 15 | bboxes = np.array([[0, 0, 50, 50], [20, 20, 60, 60]]) 16 | mmcv.imshow_bboxes(img, bboxes) 17 | ``` 18 | 19 | `mmcv` can also visualize special images such as optical flows. 20 | 21 | ```python 22 | flow = mmcv.flowread('test.flo') 23 | mmcv.flowshow(flow) 24 | ``` -------------------------------------------------------------------------------- /mmcv/examples/config_cifar10.py: -------------------------------------------------------------------------------- 1 | # model settings 2 | model = 'resnet18' 3 | # dataset settings 4 | data_root = '/mnt/SSD/dataset/cifar10' 5 | mean = [0.4914, 0.4822, 0.4465] 6 | std = [0.2023, 0.1994, 0.2010] 7 | batch_size = 64 8 | 9 | # optimizer and learning rate 10 | optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=5e-4) 11 | optimizer_config = dict(grad_clip=None) 12 | lr_config = dict(policy='step', step=2) 13 | 14 | # runtime settings 15 | work_dir = './demo' 16 | gpus = range(2) 17 | dist_params = dict(backend='nccl') 18 | data_workers = 2 # data workers per gpu 19 | checkpoint_config = dict(interval=1) # save checkpoint at every epoch 20 | workflow = [('train', 1), ('val', 1)] 21 | total_epochs = 6 22 | resume_from = None 23 | load_from = None 24 | 25 | # logging settings 26 | log_level = 'INFO' 27 | log_config = dict( 28 | interval=50, # log at every 50 iterations 29 | hooks=[ 30 | dict(type='TextLoggerHook'), 31 | # dict(type='TensorboardLoggerHook'), 32 | ]) 33 | -------------------------------------------------------------------------------- /mmcv/examples/dist_train_cifar10.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PYTHON=${PYTHON:-"python"} 4 | 5 | $PYTHON -m torch.distributed.launch --nproc_per_node=$2 train_cifar10.py $1 --launcher pytorch ${@:3} -------------------------------------------------------------------------------- /mmcv/mmcv/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | from .arraymisc import * 3 | from .utils import * 4 | from .fileio import * 5 | from .opencv_info import * 6 | from .image import * 7 | from .video import * 8 | from .visualization import * 9 | from .version import __version__ 10 | # The following modules are not imported to this level, so mmcv may be used 11 | # without PyTorch. 12 | # - runner 13 | # - parallel 14 | -------------------------------------------------------------------------------- /mmcv/mmcv/arraymisc/__init__.py: -------------------------------------------------------------------------------- 1 | from .quantization import quantize, dequantize 2 | 3 | __all__ = ['quantize', 'dequantize'] 4 | -------------------------------------------------------------------------------- /mmcv/mmcv/arraymisc/quantization.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def quantize(arr, min_val, max_val, levels, dtype=np.int64): 5 | """Quantize an array of (-inf, inf) to [0, levels-1]. 6 | 7 | Args: 8 | arr (ndarray): Input array. 9 | min_val (scalar): Minimum value to be clipped. 10 | max_val (scalar): Maximum value to be clipped. 11 | levels (int): Quantization levels. 12 | dtype (np.type): The type of the quantized array. 13 | 14 | Returns: 15 | tuple: Quantized array. 16 | """ 17 | if not (isinstance(levels, int) and levels > 1): 18 | raise ValueError( 19 | 'levels must be a positive integer, but got {}'.format(levels)) 20 | if min_val >= max_val: 21 | raise ValueError( 22 | 'min_val ({}) must be smaller than max_val ({})'.format( 23 | min_val, max_val)) 24 | 25 | arr = np.clip(arr, min_val, max_val) - min_val 26 | quantized_arr = np.minimum( 27 | np.floor(levels * arr / (max_val - min_val)).astype(dtype), levels - 1) 28 | 29 | return quantized_arr 30 | 31 | 32 | def dequantize(arr, min_val, max_val, levels, dtype=np.float64): 33 | """Dequantize an array. 34 | 35 | Args: 36 | arr (ndarray): Input array. 37 | min_val (scalar): Minimum value to be clipped. 38 | max_val (scalar): Maximum value to be clipped. 39 | levels (int): Quantization levels. 40 | dtype (np.type): The type of the dequantized array. 41 | 42 | Returns: 43 | tuple: Dequantized array. 44 | """ 45 | if not (isinstance(levels, int) and levels > 1): 46 | raise ValueError( 47 | 'levels must be a positive integer, but got {}'.format(levels)) 48 | if min_val >= max_val: 49 | raise ValueError( 50 | 'min_val ({}) must be smaller than max_val ({})'.format( 51 | min_val, max_val)) 52 | 53 | dequantized_arr = (arr + 0.5).astype(dtype) * ( 54 | max_val - min_val) / levels + min_val 55 | 56 | return dequantized_arr 57 | -------------------------------------------------------------------------------- /mmcv/mmcv/cnn/__init__.py: -------------------------------------------------------------------------------- 1 | from .alexnet import AlexNet 2 | from .vgg import VGG, make_vgg_layer 3 | from .resnet import ResNet, make_res_layer 4 | from .weight_init import (constant_init, xavier_init, normal_init, 5 | uniform_init, kaiming_init, caffe2_xavier_init) 6 | 7 | __all__ = [ 8 | 'AlexNet', 'VGG', 'make_vgg_layer', 'ResNet', 'make_res_layer', 9 | 'constant_init', 'xavier_init', 'normal_init', 'uniform_init', 10 | 'kaiming_init', 'caffe2_xavier_init' 11 | ] 12 | -------------------------------------------------------------------------------- /mmcv/mmcv/cnn/alexnet.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import torch.nn as nn 4 | 5 | from ..runner import load_checkpoint 6 | 7 | 8 | class AlexNet(nn.Module): 9 | """AlexNet backbone. 10 | 11 | Args: 12 | num_classes (int): number of classes for classification. 13 | """ 14 | 15 | def __init__(self, num_classes=-1): 16 | super(AlexNet, self).__init__() 17 | self.num_classes = num_classes 18 | self.features = nn.Sequential( 19 | nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2), 20 | nn.ReLU(inplace=True), 21 | nn.MaxPool2d(kernel_size=3, stride=2), 22 | nn.Conv2d(64, 192, kernel_size=5, padding=2), 23 | nn.ReLU(inplace=True), 24 | nn.MaxPool2d(kernel_size=3, stride=2), 25 | nn.Conv2d(192, 384, kernel_size=3, padding=1), 26 | nn.ReLU(inplace=True), 27 | nn.Conv2d(384, 256, kernel_size=3, padding=1), 28 | nn.ReLU(inplace=True), 29 | nn.Conv2d(256, 256, kernel_size=3, padding=1), 30 | nn.ReLU(inplace=True), 31 | nn.MaxPool2d(kernel_size=3, stride=2), 32 | ) 33 | if self.num_classes > 0: 34 | self.classifier = nn.Sequential( 35 | nn.Dropout(), 36 | nn.Linear(256 * 6 * 6, 4096), 37 | nn.ReLU(inplace=True), 38 | nn.Dropout(), 39 | nn.Linear(4096, 4096), 40 | nn.ReLU(inplace=True), 41 | nn.Linear(4096, num_classes), 42 | ) 43 | 44 | def init_weights(self, pretrained=None): 45 | if isinstance(pretrained, str): 46 | logger = logging.getLogger() 47 | load_checkpoint(self, pretrained, strict=False, logger=logger) 48 | elif pretrained is None: 49 | # use default initializer 50 | pass 51 | else: 52 | raise TypeError('pretrained must be a str or None') 53 | 54 | def forward(self, x): 55 | 56 | x = self.features(x) 57 | if self.num_classes > 0: 58 | x = x.view(x.size(0), 256 * 6 * 6) 59 | x = self.classifier(x) 60 | 61 | return x 62 | -------------------------------------------------------------------------------- /mmcv/mmcv/cnn/weight_init.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | def constant_init(module, val, bias=0): 5 | nn.init.constant_(module.weight, val) 6 | if hasattr(module, 'bias') and module.bias is not None: 7 | nn.init.constant_(module.bias, bias) 8 | 9 | 10 | def xavier_init(module, gain=1, bias=0, distribution='normal'): 11 | assert distribution in ['uniform', 'normal'] 12 | if distribution == 'uniform': 13 | nn.init.xavier_uniform_(module.weight, gain=gain) 14 | else: 15 | nn.init.xavier_normal_(module.weight, gain=gain) 16 | if hasattr(module, 'bias') and module.bias is not None: 17 | nn.init.constant_(module.bias, bias) 18 | 19 | 20 | def normal_init(module, mean=0, std=1, bias=0): 21 | nn.init.normal_(module.weight, mean, std) 22 | if hasattr(module, 'bias') and module.bias is not None: 23 | nn.init.constant_(module.bias, bias) 24 | 25 | 26 | def uniform_init(module, a=0, b=1, bias=0): 27 | nn.init.uniform_(module.weight, a, b) 28 | if hasattr(module, 'bias') and module.bias is not None: 29 | nn.init.constant_(module.bias, bias) 30 | 31 | 32 | def kaiming_init(module, 33 | a=0, 34 | mode='fan_out', 35 | nonlinearity='relu', 36 | bias=0, 37 | distribution='normal'): 38 | assert distribution in ['uniform', 'normal'] 39 | if distribution == 'uniform': 40 | nn.init.kaiming_uniform_( 41 | module.weight, a=a, mode=mode, nonlinearity=nonlinearity) 42 | else: 43 | nn.init.kaiming_normal_( 44 | module.weight, a=a, mode=mode, nonlinearity=nonlinearity) 45 | if hasattr(module, 'bias') and module.bias is not None: 46 | nn.init.constant_(module.bias, bias) 47 | 48 | 49 | def caffe2_xavier_init(module, bias=0): 50 | # `XavierFill` in Caffe2 corresponds to `kaiming_uniform_` in PyTorch 51 | # Acknowledgment to FAIR's internal code 52 | kaiming_init( 53 | module, 54 | a=1, 55 | mode='fan_in', 56 | nonlinearity='leaky_relu', 57 | distribution='uniform') 58 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/__init__.py: -------------------------------------------------------------------------------- 1 | from .io import load, dump, register_handler 2 | from .handlers import BaseFileHandler, JsonHandler, PickleHandler, YamlHandler 3 | from .parse import list_from_file, dict_from_file 4 | 5 | __all__ = [ 6 | 'load', 'dump', 'register_handler', 'BaseFileHandler', 'JsonHandler', 7 | 'PickleHandler', 'YamlHandler', 'list_from_file', 'dict_from_file' 8 | ] 9 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/handlers/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import BaseFileHandler 2 | from .json_handler import JsonHandler 3 | from .pickle_handler import PickleHandler 4 | from .yaml_handler import YamlHandler 5 | 6 | __all__ = ['BaseFileHandler', 'JsonHandler', 'PickleHandler', 'YamlHandler'] 7 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/handlers/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | 4 | class BaseFileHandler(object): 5 | 6 | __metaclass__ = ABCMeta # python 2 compatibility 7 | 8 | @abstractmethod 9 | def load_from_fileobj(self, file, **kwargs): 10 | pass 11 | 12 | @abstractmethod 13 | def dump_to_fileobj(self, obj, file, **kwargs): 14 | pass 15 | 16 | @abstractmethod 17 | def dump_to_str(self, obj, **kwargs): 18 | pass 19 | 20 | def load_from_path(self, filepath, mode='r', **kwargs): 21 | with open(filepath, mode) as f: 22 | return self.load_from_fileobj(f, **kwargs) 23 | 24 | def dump_to_path(self, obj, filepath, mode='w', **kwargs): 25 | with open(filepath, mode) as f: 26 | self.dump_to_fileobj(obj, f, **kwargs) 27 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/handlers/json_handler.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .base import BaseFileHandler 4 | 5 | 6 | class JsonHandler(BaseFileHandler): 7 | 8 | def load_from_fileobj(self, file): 9 | return json.load(file) 10 | 11 | def dump_to_fileobj(self, obj, file, **kwargs): 12 | json.dump(obj, file, **kwargs) 13 | 14 | def dump_to_str(self, obj, **kwargs): 15 | return json.dumps(obj, **kwargs) 16 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/handlers/pickle_handler.py: -------------------------------------------------------------------------------- 1 | from six.moves import cPickle as pickle 2 | 3 | from .base import BaseFileHandler 4 | 5 | 6 | class PickleHandler(BaseFileHandler): 7 | 8 | def load_from_fileobj(self, file, **kwargs): 9 | return pickle.load(file, **kwargs) 10 | 11 | def load_from_path(self, filepath, **kwargs): 12 | return super(PickleHandler, self).load_from_path( 13 | filepath, mode='rb', **kwargs) 14 | 15 | def dump_to_str(self, obj, **kwargs): 16 | kwargs.setdefault('protocol', 2) 17 | return pickle.dumps(obj, **kwargs) 18 | 19 | def dump_to_fileobj(self, obj, file, **kwargs): 20 | kwargs.setdefault('protocol', 2) 21 | pickle.dump(obj, file, **kwargs) 22 | 23 | def dump_to_path(self, obj, filepath, **kwargs): 24 | super(PickleHandler, self).dump_to_path( 25 | obj, filepath, mode='wb', **kwargs) 26 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/handlers/yaml_handler.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | try: 3 | from yaml import CLoader as Loader, CDumper as Dumper 4 | except ImportError: 5 | from yaml import Loader, Dumper 6 | 7 | from .base import BaseFileHandler 8 | 9 | 10 | class YamlHandler(BaseFileHandler): 11 | 12 | def load_from_fileobj(self, file, **kwargs): 13 | kwargs.setdefault('Loader', Loader) 14 | return yaml.load(file, **kwargs) 15 | 16 | def dump_to_fileobj(self, obj, file, **kwargs): 17 | kwargs.setdefault('Dumper', Dumper) 18 | yaml.dump(obj, file, **kwargs) 19 | 20 | def dump_to_str(self, obj, **kwargs): 21 | kwargs.setdefault('Dumper', Dumper) 22 | return yaml.dump(obj, **kwargs) 23 | -------------------------------------------------------------------------------- /mmcv/mmcv/fileio/parse.py: -------------------------------------------------------------------------------- 1 | def list_from_file(filename, prefix='', offset=0, max_num=0): 2 | """Load a text file and parse the content as a list of strings. 3 | 4 | Args: 5 | filename (str): Filename. 6 | prefix (str): The prefix to be inserted to the begining of each item. 7 | offset (int): The offset of lines. 8 | max_num (int): The maximum number of lines to be read, 9 | zeros and negatives mean no limitation. 10 | 11 | Returns: 12 | list[str]: A list of strings. 13 | """ 14 | cnt = 0 15 | item_list = [] 16 | with open(filename, 'r') as f: 17 | for _ in range(offset): 18 | f.readline() 19 | for line in f: 20 | if max_num > 0 and cnt >= max_num: 21 | break 22 | item_list.append(prefix + line.rstrip('\n')) 23 | cnt += 1 24 | return item_list 25 | 26 | 27 | def dict_from_file(filename, key_type=str): 28 | """Load a text file and parse the content as a dict. 29 | 30 | Each line of the text file will be two or more columns splited by 31 | whitespaces or tabs. The first column will be parsed as dict keys, and 32 | the following columns will be parsed as dict values. 33 | 34 | Args: 35 | filename(str): Filename. 36 | key_type(type): Type of the dict's keys. str is user by default and 37 | type conversion will be performed if specified. 38 | 39 | Returns: 40 | dict: The parsed contents. 41 | """ 42 | mapping = {} 43 | with open(filename, 'r') as f: 44 | for line in f: 45 | items = line.rstrip('\n').split() 46 | assert len(items) >= 2 47 | key = key_type(items[0]) 48 | val = items[1:] if len(items) > 2 else items[1] 49 | mapping[key] = val 50 | return mapping 51 | -------------------------------------------------------------------------------- /mmcv/mmcv/image/__init__.py: -------------------------------------------------------------------------------- 1 | from .io import imread, imwrite, imfrombytes 2 | from .transforms import (bgr2gray, gray2bgr, bgr2rgb, rgb2bgr, bgr2hsv, 3 | hsv2bgr, bgr2hls, hls2bgr, iminvert, imflip, imrotate, 4 | imcrop, impad, impad_to_multiple, imnormalize, 5 | imdenormalize, imresize, imresize_like, imrescale) 6 | 7 | __all__ = [ 8 | 'imread', 'imwrite', 'imfrombytes', 'bgr2gray', 'gray2bgr', 'bgr2rgb', 9 | 'rgb2bgr', 'bgr2hsv', 'hsv2bgr', 'bgr2hls', 'hls2bgr', 'iminvert', 10 | 'imflip', 'imrotate', 'imcrop', 'impad', 'impad_to_multiple', 11 | 'imnormalize', 'imdenormalize', 'imresize', 'imresize_like', 'imrescale' 12 | ] 13 | -------------------------------------------------------------------------------- /mmcv/mmcv/image/transforms/__init__.py: -------------------------------------------------------------------------------- 1 | from .colorspace import (bgr2gray, gray2bgr, bgr2rgb, rgb2bgr, bgr2hsv, 2 | hsv2bgr, bgr2hls, hls2bgr, iminvert) 3 | from .geometry import imflip, imrotate, imcrop, impad, impad_to_multiple 4 | from .normalize import imnormalize, imdenormalize 5 | from .resize import imresize, imresize_like, imrescale 6 | 7 | __all__ = [ 8 | 'bgr2gray', 'gray2bgr', 'bgr2rgb', 'rgb2bgr', 'bgr2hsv', 'hsv2bgr', 9 | 'bgr2hls', 'hls2bgr', 'iminvert', 'imflip', 'imrotate', 'imcrop', 'impad', 10 | 'impad_to_multiple', 'imnormalize', 'imdenormalize', 'imresize', 11 | 'imresize_like', 'imrescale' 12 | ] 13 | -------------------------------------------------------------------------------- /mmcv/mmcv/image/transforms/colorspace.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | 5 | def iminvert(img): 6 | """Invert (negate) an image 7 | Args: 8 | img (ndarray): Image to be inverted. 9 | 10 | Returns: 11 | ndarray: The inverted image. 12 | """ 13 | return np.full_like(img, 255) - img 14 | 15 | 16 | def bgr2gray(img, keepdim=False): 17 | """Convert a BGR image to grayscale image. 18 | 19 | Args: 20 | img (ndarray): The input image. 21 | keepdim (bool): If False (by default), then return the grayscale image 22 | with 2 dims, otherwise 3 dims. 23 | 24 | Returns: 25 | ndarray: The converted grayscale image. 26 | """ 27 | out_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 28 | if keepdim: 29 | out_img = out_img[..., None] 30 | return out_img 31 | 32 | 33 | def gray2bgr(img): 34 | """Convert a grayscale image to BGR image. 35 | 36 | Args: 37 | img (ndarray or str): The input image. 38 | 39 | Returns: 40 | ndarray: The converted BGR image. 41 | """ 42 | img = img[..., None] if img.ndim == 2 else img 43 | out_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) 44 | return out_img 45 | 46 | 47 | def convert_color_factory(src, dst): 48 | 49 | code = getattr(cv2, 'COLOR_{}2{}'.format(src.upper(), dst.upper())) 50 | 51 | def convert_color(img): 52 | out_img = cv2.cvtColor(img, code) 53 | return out_img 54 | 55 | convert_color.__doc__ = """Convert a {0} image to {1} image. 56 | 57 | Args: 58 | img (ndarray or str): The input image. 59 | 60 | Returns: 61 | ndarray: The converted {1} image. 62 | """.format(src.upper(), dst.upper()) 63 | 64 | return convert_color 65 | 66 | 67 | bgr2rgb = convert_color_factory('bgr', 'rgb') 68 | 69 | rgb2bgr = convert_color_factory('rgb', 'bgr') 70 | 71 | bgr2hsv = convert_color_factory('bgr', 'hsv') 72 | 73 | hsv2bgr = convert_color_factory('hsv', 'bgr') 74 | 75 | bgr2hls = convert_color_factory('bgr', 'hls') 76 | 77 | hls2bgr = convert_color_factory('hls', 'bgr') 78 | -------------------------------------------------------------------------------- /mmcv/mmcv/image/transforms/normalize.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from .colorspace import bgr2rgb, rgb2bgr 4 | 5 | 6 | def imnormalize(img, mean, std, to_rgb=True): 7 | img = img.astype(np.float32) 8 | if to_rgb: 9 | img = bgr2rgb(img) 10 | return (img - mean) / std 11 | 12 | 13 | def imdenormalize(img, mean, std, to_bgr=True): 14 | img = (img * std) + mean 15 | if to_bgr: 16 | img = rgb2bgr(img) 17 | return img 18 | -------------------------------------------------------------------------------- /mmcv/mmcv/opencv_info.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | 4 | def use_opencv2(): 5 | try: 6 | major_version = cv2.__version__.split('.')[0] 7 | except TypeError: # solves doc generation issue 8 | major_version = 4 9 | return major_version == '2' 10 | 11 | 12 | USE_OPENCV2 = use_opencv2() 13 | -------------------------------------------------------------------------------- /mmcv/mmcv/parallel/__init__.py: -------------------------------------------------------------------------------- 1 | from .collate import collate 2 | from .data_container import DataContainer 3 | from .data_parallel import MMDataParallel 4 | from .distributed import MMDistributedDataParallel 5 | from .scatter_gather import scatter, scatter_kwargs 6 | 7 | __all__ = [ 8 | 'collate', 'DataContainer', 'MMDataParallel', 'MMDistributedDataParallel', 9 | 'scatter', 'scatter_kwargs' 10 | ] 11 | -------------------------------------------------------------------------------- /mmcv/mmcv/parallel/data_parallel.py: -------------------------------------------------------------------------------- 1 | from torch.nn.parallel import DataParallel 2 | 3 | from .scatter_gather import scatter_kwargs 4 | 5 | 6 | class MMDataParallel(DataParallel): 7 | 8 | def scatter(self, inputs, kwargs, device_ids): 9 | return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) 10 | -------------------------------------------------------------------------------- /mmcv/mmcv/parallel/distributed.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.distributed as dist 3 | import torch.nn as nn 4 | from torch._utils import (_flatten_dense_tensors, _unflatten_dense_tensors, 5 | _take_tensors) 6 | 7 | from .scatter_gather import scatter_kwargs 8 | 9 | 10 | class MMDistributedDataParallel(nn.Module): 11 | 12 | def __init__(self, module, dim=0, broadcast_buffers=True, 13 | bucket_cap_mb=25): 14 | super(MMDistributedDataParallel, self).__init__() 15 | self.module = module 16 | self.dim = dim 17 | self.broadcast_buffers = broadcast_buffers 18 | 19 | self.broadcast_bucket_size = bucket_cap_mb * 1024 * 1024 20 | self._sync_params() 21 | 22 | def _dist_broadcast_coalesced(self, tensors, buffer_size): 23 | for tensors in _take_tensors(tensors, buffer_size): 24 | flat_tensors = _flatten_dense_tensors(tensors) 25 | dist.broadcast(flat_tensors, 0) 26 | for tensor, synced in zip( 27 | tensors, _unflatten_dense_tensors(flat_tensors, tensors)): 28 | tensor.copy_(synced) 29 | 30 | def _sync_params(self): 31 | module_states = list(self.module.state_dict().values()) 32 | if len(module_states) > 0: 33 | self._dist_broadcast_coalesced(module_states, 34 | self.broadcast_bucket_size) 35 | if self.broadcast_buffers: 36 | if torch.__version__ < '1.0': 37 | buffers = [b.data for b in self.module._all_buffers()] 38 | else: 39 | buffers = [b.data for b in self.module.buffers()] 40 | if len(buffers) > 0: 41 | self._dist_broadcast_coalesced(buffers, 42 | self.broadcast_bucket_size) 43 | 44 | def scatter(self, inputs, kwargs, device_ids): 45 | return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) 46 | 47 | def forward(self, *inputs, **kwargs): 48 | inputs, kwargs = self.scatter(inputs, kwargs, 49 | [torch.cuda.current_device()]) 50 | return self.module(*inputs[0], **kwargs[0]) 51 | -------------------------------------------------------------------------------- /mmcv/mmcv/parallel/scatter_gather.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.nn.parallel._functions import Scatter as OrigScatter 3 | 4 | from ._functions import Scatter 5 | from .data_container import DataContainer 6 | 7 | 8 | def scatter(inputs, target_gpus, dim=0): 9 | """Scatter inputs to target gpus. 10 | 11 | The only difference from original :func:`scatter` is to add support for 12 | :type:`~mmcv.parallel.DataContainer`. 13 | """ 14 | 15 | def scatter_map(obj): 16 | if isinstance(obj, torch.Tensor): 17 | return OrigScatter.apply(target_gpus, None, dim, obj) 18 | if isinstance(obj, DataContainer): 19 | if obj.cpu_only: 20 | return obj.data 21 | else: 22 | return Scatter.forward(target_gpus, obj.data) 23 | if isinstance(obj, tuple) and len(obj) > 0: 24 | return list(zip(*map(scatter_map, obj))) 25 | if isinstance(obj, list) and len(obj) > 0: 26 | out = list(map(list, zip(*map(scatter_map, obj)))) 27 | return out 28 | if isinstance(obj, dict) and len(obj) > 0: 29 | out = list(map(type(obj), zip(*map(scatter_map, obj.items())))) 30 | return out 31 | return [obj for targets in target_gpus] 32 | 33 | # After scatter_map is called, a scatter_map cell will exist. This cell 34 | # has a reference to the actual function scatter_map, which has references 35 | # to a closure that has a reference to the scatter_map cell (because the 36 | # fn is recursive). To avoid this reference cycle, we set the function to 37 | # None, clearing the cell 38 | try: 39 | return scatter_map(inputs) 40 | finally: 41 | scatter_map = None 42 | 43 | 44 | def scatter_kwargs(inputs, kwargs, target_gpus, dim=0): 45 | """Scatter with support for kwargs dictionary""" 46 | inputs = scatter(inputs, target_gpus, dim) if inputs else [] 47 | kwargs = scatter(kwargs, target_gpus, dim) if kwargs else [] 48 | if len(inputs) < len(kwargs): 49 | inputs.extend([() for _ in range(len(kwargs) - len(inputs))]) 50 | elif len(kwargs) < len(inputs): 51 | kwargs.extend([{} for _ in range(len(inputs) - len(kwargs))]) 52 | inputs = tuple(inputs) 53 | kwargs = tuple(kwargs) 54 | return inputs, kwargs 55 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/__init__.py: -------------------------------------------------------------------------------- 1 | from .runner import Runner 2 | from .log_buffer import LogBuffer 3 | from .hooks import (Hook, CheckpointHook, ClosureHook, LrUpdaterHook, 4 | OptimizerHook, IterTimerHook, DistSamplerSeedHook, 5 | LoggerHook, TextLoggerHook, PaviLoggerHook, 6 | TensorboardLoggerHook) 7 | from .checkpoint import (load_state_dict, load_checkpoint, weights_to_cpu, 8 | save_checkpoint) 9 | from .parallel_test import parallel_test 10 | from .priority import Priority, get_priority 11 | from .utils import (get_host_info, get_dist_info, master_only, get_time_str, 12 | obj_from_dict) 13 | 14 | __all__ = [ 15 | 'Runner', 'LogBuffer', 'Hook', 'CheckpointHook', 'ClosureHook', 16 | 'LrUpdaterHook', 'OptimizerHook', 'IterTimerHook', 'DistSamplerSeedHook', 17 | 'LoggerHook', 'TextLoggerHook', 'PaviLoggerHook', 'TensorboardLoggerHook', 18 | 'load_state_dict', 'load_checkpoint', 'weights_to_cpu', 'save_checkpoint', 19 | 'parallel_test', 'Priority', 'get_priority', 'get_host_info', 20 | 'get_dist_info', 'master_only', 'get_time_str', 'obj_from_dict' 21 | ] 22 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/__init__.py: -------------------------------------------------------------------------------- 1 | from .hook import Hook 2 | from .checkpoint import CheckpointHook 3 | from .closure import ClosureHook 4 | from .lr_updater import LrUpdaterHook 5 | from .optimizer import OptimizerHook 6 | from .iter_timer import IterTimerHook 7 | from .sampler_seed import DistSamplerSeedHook 8 | from .memory import EmptyCacheHook 9 | from .logger import (LoggerHook, TextLoggerHook, PaviLoggerHook, 10 | TensorboardLoggerHook) 11 | 12 | __all__ = [ 13 | 'Hook', 'CheckpointHook', 'ClosureHook', 'LrUpdaterHook', 'OptimizerHook', 14 | 'IterTimerHook', 'DistSamplerSeedHook', 'EmptyCacheHook', 'LoggerHook', 15 | 'TextLoggerHook', 'PaviLoggerHook', 'TensorboardLoggerHook' 16 | ] 17 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/checkpoint.py: -------------------------------------------------------------------------------- 1 | from .hook import Hook 2 | from ..utils import master_only 3 | 4 | 5 | class CheckpointHook(Hook): 6 | 7 | def __init__(self, 8 | interval=-1, 9 | save_optimizer=True, 10 | out_dir=None, 11 | **kwargs): 12 | self.interval = interval 13 | self.save_optimizer = save_optimizer 14 | self.out_dir = out_dir 15 | self.args = kwargs 16 | 17 | @master_only 18 | def after_train_epoch(self, runner): 19 | if not self.every_n_epochs(runner, self.interval): 20 | return 21 | 22 | if not self.out_dir: 23 | self.out_dir = runner.work_dir 24 | runner.save_checkpoint( 25 | self.out_dir, save_optimizer=self.save_optimizer, **self.args) 26 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/closure.py: -------------------------------------------------------------------------------- 1 | from .hook import Hook 2 | 3 | 4 | class ClosureHook(Hook): 5 | 6 | def __init__(self, fn_name, fn): 7 | assert hasattr(self, fn_name) 8 | assert callable(fn) 9 | setattr(self, fn_name, fn) 10 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/hook.py: -------------------------------------------------------------------------------- 1 | class Hook(object): 2 | 3 | def before_run(self, runner): 4 | pass 5 | 6 | def after_run(self, runner): 7 | pass 8 | 9 | def before_epoch(self, runner): 10 | pass 11 | 12 | def after_epoch(self, runner): 13 | pass 14 | 15 | def before_iter(self, runner): 16 | pass 17 | 18 | def after_iter(self, runner): 19 | pass 20 | 21 | def before_train_epoch(self, runner): 22 | self.before_epoch(runner) 23 | 24 | def before_val_epoch(self, runner): 25 | self.before_epoch(runner) 26 | 27 | def after_train_epoch(self, runner): 28 | self.after_epoch(runner) 29 | 30 | def after_val_epoch(self, runner): 31 | self.after_epoch(runner) 32 | 33 | def before_train_iter(self, runner): 34 | self.before_iter(runner) 35 | 36 | def before_val_iter(self, runner): 37 | self.before_iter(runner) 38 | 39 | def after_train_iter(self, runner): 40 | self.after_iter(runner) 41 | 42 | def after_val_iter(self, runner): 43 | self.after_iter(runner) 44 | 45 | def every_n_epochs(self, runner, n): 46 | return (runner.epoch + 1) % n == 0 if n > 0 else False 47 | 48 | def every_n_inner_iters(self, runner, n): 49 | return (runner.inner_iter + 1) % n == 0 if n > 0 else False 50 | 51 | def every_n_iters(self, runner, n): 52 | return (runner.iter + 1) % n == 0 if n > 0 else False 53 | 54 | def end_of_epoch(self, runner): 55 | return runner.inner_iter + 1 == len(runner.data_loader) 56 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/iter_timer.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from .hook import Hook 4 | 5 | 6 | class IterTimerHook(Hook): 7 | 8 | def before_epoch(self, runner): 9 | self.t = time.time() 10 | 11 | def before_iter(self, runner): 12 | runner.log_buffer.update({'data_time': time.time() - self.t}) 13 | 14 | def after_iter(self, runner): 15 | runner.log_buffer.update({'time': time.time() - self.t}) 16 | self.t = time.time() 17 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/logger/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import LoggerHook 2 | from .pavi import PaviLoggerHook 3 | from .tensorboard import TensorboardLoggerHook 4 | from .text import TextLoggerHook 5 | 6 | __all__ = [ 7 | 'LoggerHook', 'TextLoggerHook', 'PaviLoggerHook', 'TensorboardLoggerHook' 8 | ] 9 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/logger/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | from ..hook import Hook 4 | 5 | 6 | class LoggerHook(Hook): 7 | """Base class for logger hooks. 8 | 9 | Args: 10 | interval (int): Logging interval (every k iterations). 11 | ignore_last (bool): Ignore the log of last iterations in each epoch 12 | if less than `interval`. 13 | reset_flag (bool): Whether to clear the output buffer after logging. 14 | """ 15 | 16 | __metaclass__ = ABCMeta 17 | 18 | def __init__(self, interval=10, ignore_last=True, reset_flag=False): 19 | self.interval = interval 20 | self.ignore_last = ignore_last 21 | self.reset_flag = reset_flag 22 | 23 | @abstractmethod 24 | def log(self, runner): 25 | pass 26 | 27 | def before_run(self, runner): 28 | for hook in runner.hooks[::-1]: 29 | if isinstance(hook, LoggerHook): 30 | hook.reset_flag = True 31 | break 32 | 33 | def before_epoch(self, runner): 34 | runner.log_buffer.clear() # clear logs of last epoch 35 | 36 | def after_train_iter(self, runner): 37 | if self.every_n_inner_iters(runner, self.interval): 38 | runner.log_buffer.average(self.interval) 39 | elif self.end_of_epoch(runner) and not self.ignore_last: 40 | # not precise but more stable 41 | runner.log_buffer.average(self.interval) 42 | 43 | if runner.log_buffer.ready: 44 | self.log(runner) 45 | if self.reset_flag: 46 | runner.log_buffer.clear_output() 47 | 48 | def after_train_epoch(self, runner): 49 | if runner.log_buffer.ready: 50 | self.log(runner) 51 | if self.reset_flag: 52 | runner.log_buffer.clear_output() 53 | 54 | def after_val_epoch(self, runner): 55 | runner.log_buffer.average() 56 | self.log(runner) 57 | if self.reset_flag: 58 | runner.log_buffer.clear_output() 59 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/logger/tensorboard.py: -------------------------------------------------------------------------------- 1 | import os.path as osp 2 | 3 | from .base import LoggerHook 4 | from ...utils import master_only 5 | 6 | 7 | class TensorboardLoggerHook(LoggerHook): 8 | 9 | def __init__(self, 10 | log_dir=None, 11 | interval=10, 12 | ignore_last=True, 13 | reset_flag=True): 14 | super(TensorboardLoggerHook, self).__init__(interval, ignore_last, 15 | reset_flag) 16 | self.log_dir = log_dir 17 | 18 | @master_only 19 | def before_run(self, runner): 20 | try: 21 | from tensorboardX import SummaryWriter 22 | except ImportError: 23 | raise ImportError('Please install tensorflow and tensorboardX ' 24 | 'to use TensorboardLoggerHook.') 25 | else: 26 | if self.log_dir is None: 27 | self.log_dir = osp.join(runner.work_dir, 'tf_logs') 28 | self.writer = SummaryWriter(self.log_dir) 29 | 30 | @master_only 31 | def log(self, runner): 32 | for var in runner.log_buffer.output: 33 | if var in ['time', 'data_time']: 34 | continue 35 | tag = '{}/{}'.format(var, runner.mode) 36 | record = runner.log_buffer.output[var] 37 | if isinstance(record, str): 38 | self.writer.add_text(tag, record, runner.iter) 39 | else: 40 | self.writer.add_scalar(tag, runner.log_buffer.output[var], 41 | runner.iter) 42 | 43 | @master_only 44 | def after_run(self, runner): 45 | self.writer.close() 46 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/memory.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from .hook import Hook 4 | 5 | 6 | class EmptyCacheHook(Hook): 7 | 8 | def __init__(self, before_epoch=False, after_epoch=True, after_iter=False): 9 | self._before_epoch = before_epoch 10 | self._after_epoch = after_epoch 11 | self._after_iter = after_iter 12 | 13 | def after_iter(self, runner): 14 | if self._after_iter: 15 | torch.cuda.empty_cache() 16 | 17 | def before_epoch(self, runner): 18 | if self._before_epoch: 19 | torch.cuda.empty_cache() 20 | 21 | def after_epoch(self, runner): 22 | if self._after_epoch: 23 | torch.cuda.empty_cache() 24 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/optimizer.py: -------------------------------------------------------------------------------- 1 | from torch.nn.utils import clip_grad 2 | 3 | from .hook import Hook 4 | 5 | 6 | class OptimizerHook(Hook): 7 | 8 | def __init__(self, grad_clip=None): 9 | self.grad_clip = grad_clip 10 | 11 | def clip_grads(self, params): 12 | clip_grad.clip_grad_norm_( 13 | filter(lambda p: p.requires_grad, params), **self.grad_clip) 14 | 15 | def after_train_iter(self, runner): 16 | runner.optimizer.zero_grad() 17 | runner.outputs['loss'].backward() 18 | # import torch 19 | # named_parameters = dict(runner.model.module.named_parameters()) 20 | # for k, v in named_parameters.items(): 21 | # if v.grad is not None and torch.any(torch.isnan(v.grad)): 22 | # import ipdb 23 | # ipdb.set_trace() 24 | if self.grad_clip is not None: 25 | self.clip_grads(runner.model.parameters()) 26 | runner.optimizer.step() 27 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/hooks/sampler_seed.py: -------------------------------------------------------------------------------- 1 | from .hook import Hook 2 | 3 | 4 | class DistSamplerSeedHook(Hook): 5 | 6 | def before_epoch(self, runner): 7 | runner.data_loader.sampler.set_epoch(runner.epoch) 8 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/log_buffer.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | import numpy as np 4 | 5 | 6 | class LogBuffer(object): 7 | 8 | def __init__(self): 9 | self.val_history = OrderedDict() 10 | self.n_history = OrderedDict() 11 | self.output = OrderedDict() 12 | self.ready = False 13 | 14 | def clear(self): 15 | self.val_history.clear() 16 | self.n_history.clear() 17 | self.clear_output() 18 | 19 | def clear_output(self): 20 | self.output.clear() 21 | self.ready = False 22 | 23 | def update(self, vars, count=1): 24 | assert isinstance(vars, dict) 25 | for key, var in vars.items(): 26 | if key not in self.val_history: 27 | self.val_history[key] = [] 28 | self.n_history[key] = [] 29 | self.val_history[key].append(var) 30 | self.n_history[key].append(count) 31 | 32 | def average(self, n=0): 33 | """Average latest n values or all values""" 34 | assert n >= 0 35 | for key in self.val_history: 36 | if key.startswith('img$'): 37 | # Hack to avoid the modification on image 38 | if key not in self.output: 39 | self.output[key] = list() 40 | self.output[key].extend(self.val_history[key]) 41 | self.val_history[key] = list() 42 | self.n_history[key] = list() 43 | else: 44 | values = np.array(self.val_history[key][-n:]) 45 | nums = np.array(self.n_history[key][-n:]) 46 | avg = np.sum(values * nums) / np.sum(nums) 47 | self.output[key] = avg 48 | self.ready = True 49 | -------------------------------------------------------------------------------- /mmcv/mmcv/runner/priority.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Priority(Enum): 5 | """Hook priority levels. 6 | 7 | +------------+------------+ 8 | | Level | Value | 9 | +============+============+ 10 | | HIGHEST | 0 | 11 | +------------+------------+ 12 | | VERY_HIGH | 10 | 13 | +------------+------------+ 14 | | HIGH | 30 | 15 | +------------+------------+ 16 | | NORMAL | 50 | 17 | +------------+------------+ 18 | | LOW | 70 | 19 | +------------+------------+ 20 | | VERY_LOW | 90 | 21 | +------------+------------+ 22 | | LOWEST | 100 | 23 | +------------+------------+ 24 | """ 25 | 26 | HIGHEST = 0 27 | VERY_HIGH = 10 28 | HIGH = 30 29 | NORMAL = 50 30 | LOW = 70 31 | VERY_LOW = 90 32 | LOWEST = 100 33 | 34 | 35 | def get_priority(priority): 36 | """Get priority value. 37 | 38 | Args: 39 | priority (int or str or :obj:`Priority`): Priority. 40 | 41 | Returns: 42 | int: The priority value. 43 | """ 44 | if isinstance(priority, int): 45 | if priority < 0 or priority > 100: 46 | raise ValueError('priority must be between 0 and 100') 47 | return priority 48 | elif isinstance(priority, Priority): 49 | return priority.value 50 | elif isinstance(priority, str): 51 | return Priority[priority.upper()].value 52 | else: 53 | raise TypeError('priority must be an integer or Priority enum value') 54 | -------------------------------------------------------------------------------- /mmcv/mmcv/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import ConfigDict, Config 2 | from .misc import (is_str, iter_cast, list_cast, tuple_cast, is_seq_of, 3 | is_list_of, is_tuple_of, slice_list, concat_list, 4 | check_prerequisites, requires_package, requires_executable) 5 | from .path import (is_filepath, fopen, check_file_exist, mkdir_or_exist, 6 | symlink, scandir, FileNotFoundError) 7 | from .progressbar import ProgressBar, track_progress, track_parallel_progress 8 | from .timer import Timer, TimerError, check_time 9 | 10 | __all__ = [ 11 | 'ConfigDict', 'Config', 'is_str', 'iter_cast', 'list_cast', 'tuple_cast', 12 | 'is_seq_of', 'is_list_of', 'is_tuple_of', 'slice_list', 'concat_list', 13 | 'check_prerequisites', 'requires_package', 'requires_executable', 14 | 'is_filepath', 'fopen', 'check_file_exist', 'mkdir_or_exist', 'symlink', 15 | 'scandir', 'FileNotFoundError', 'ProgressBar', 'track_progress', 16 | 'track_parallel_progress', 'Timer', 'TimerError', 'check_time' 17 | ] 18 | -------------------------------------------------------------------------------- /mmcv/mmcv/utils/path.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path as osp 3 | import sys 4 | from pathlib import Path 5 | 6 | import six 7 | 8 | from .misc import is_str 9 | 10 | if sys.version_info <= (3, 3): 11 | FileNotFoundError = IOError 12 | else: 13 | FileNotFoundError = FileNotFoundError 14 | 15 | 16 | def is_filepath(x): 17 | if is_str(x) or isinstance(x, Path): 18 | return True 19 | else: 20 | return False 21 | 22 | 23 | def fopen(filepath, *args, **kwargs): 24 | if is_str(filepath): 25 | return open(filepath, *args, **kwargs) 26 | elif isinstance(filepath, Path): 27 | return filepath.open(*args, **kwargs) 28 | 29 | 30 | def check_file_exist(filename, msg_tmpl='file "{}" does not exist'): 31 | if not osp.isfile(filename): 32 | raise FileNotFoundError(msg_tmpl.format(filename)) 33 | 34 | 35 | def mkdir_or_exist(dir_name, mode=0o777): 36 | if dir_name == '': 37 | return 38 | dir_name = osp.expanduser(dir_name) 39 | if six.PY3: 40 | os.makedirs(dir_name, mode=mode, exist_ok=True) 41 | else: 42 | if not osp.isdir(dir_name): 43 | os.makedirs(dir_name, mode=mode) 44 | 45 | 46 | def symlink(src, dst, overwrite=True, **kwargs): 47 | if os.path.lexists(dst) and overwrite: 48 | os.remove(dst) 49 | os.symlink(src, dst, **kwargs) 50 | 51 | 52 | def _scandir_py35(dir_path, suffix=None): 53 | for entry in os.scandir(dir_path): 54 | if not entry.is_file(): 55 | continue 56 | filename = entry.name 57 | if suffix is None: 58 | yield filename 59 | elif filename.endswith(suffix): 60 | yield filename 61 | 62 | 63 | def _scandir_py(dir_path, suffix=None): 64 | for filename in os.listdir(dir_path): 65 | if not osp.isfile(osp.join(dir_path, filename)): 66 | continue 67 | if suffix is None: 68 | yield filename 69 | elif filename.endswith(suffix): 70 | yield filename 71 | 72 | 73 | def scandir(dir_path, suffix=None): 74 | if suffix is not None and not isinstance(suffix, (str, tuple)): 75 | raise TypeError('"suffix" must be a string or tuple of strings') 76 | if sys.version_info >= (3, 5): 77 | return _scandir_py35(dir_path, suffix) 78 | else: 79 | return _scandir_py(dir_path, suffix) 80 | -------------------------------------------------------------------------------- /mmcv/mmcv/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.2.10' 2 | -------------------------------------------------------------------------------- /mmcv/mmcv/video/__init__.py: -------------------------------------------------------------------------------- 1 | from .io import Cache, VideoReader, frames2video 2 | from .processing import convert_video, resize_video, cut_video, concat_video 3 | from .optflow import (flowread, flowwrite, quantize_flow, 4 | dequantize_flow, flow_warp) 5 | 6 | __all__ = [ 7 | 'Cache', 'VideoReader', 'frames2video', 'convert_video', 'resize_video', 8 | 'cut_video', 'concat_video', 'flowread', 'flowwrite', 'quantize_flow', 9 | 'dequantize_flow', 'flow_warp' 10 | ] 11 | -------------------------------------------------------------------------------- /mmcv/mmcv/video/optflow_warp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmcv/mmcv/video/optflow_warp/__init__.py -------------------------------------------------------------------------------- /mmcv/mmcv/video/optflow_warp/flow_warp.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void FlowWarp(double* img, double* flow1, double* out, const int height, 8 | const int width, const int channels, const int filling_value, 9 | const int interpolateMode); 10 | 11 | void BilinearInterpolate(const double* img, int width, int height, int channels, 12 | double x, double y, double* out); 13 | 14 | void NNInterpolate(const double* img, int width, int height, int channels, 15 | double x, double y, double* out); 16 | 17 | template 18 | inline T __min__(T a, T b) { 19 | return a > b ? b : a; 20 | } 21 | 22 | template 23 | inline T __max__(T a, T b) { 24 | return (a < b) ? b : a; 25 | } 26 | 27 | template 28 | inline T EnforceRange(const T x, const int MaxValue) { 29 | return __min__(__max__(x, 0), MaxValue); 30 | } 31 | -------------------------------------------------------------------------------- /mmcv/mmcv/video/optflow_warp/flow_warp_module.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | import numpy as np 4 | cimport numpy as np 5 | 6 | np.import_array() 7 | 8 | cdef extern from "flow_warp.hpp": 9 | void FlowWarp(double* img, double* flow1, double* out, const int height, const int width, const int channels, const int filling_value, const int interpolateMode) 10 | 11 | def flow_warp_c(np.ndarray[double, ndim=3, mode="c"] img_array not None, 12 | np.ndarray[double, ndim=3, mode="c"] flow_array not None, 13 | int filling_value=0, 14 | int interpolate_mode=1): 15 | 16 | out_array = np.zeros_like(img_array) 17 | 18 | FlowWarp( np.PyArray_DATA(img_array), 19 | np.PyArray_DATA(flow_array), 20 | np.PyArray_DATA(out_array), 21 | out_array.shape[0], 22 | out_array.shape[1], 23 | out_array.shape[2], 24 | filling_value, 25 | interpolate_mode) 26 | 27 | return out_array 28 | -------------------------------------------------------------------------------- /mmcv/mmcv/visualization/__init__.py: -------------------------------------------------------------------------------- 1 | from .color import Color, color_val 2 | from .image import imshow, imshow_bboxes, imshow_det_bboxes 3 | from .optflow import flowshow, flow2rgb, make_color_wheel 4 | 5 | __all__ = [ 6 | 'Color', 'color_val', 'imshow', 'imshow_bboxes', 'imshow_det_bboxes', 7 | 'flowshow', 'flow2rgb', 'make_color_wheel' 8 | ] 9 | -------------------------------------------------------------------------------- /mmcv/mmcv/visualization/color.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | import numpy as np 4 | 5 | from mmcv.utils import is_str 6 | 7 | 8 | class Color(Enum): 9 | """An enum that defines common colors. 10 | 11 | Contains red, green, blue, cyan, yellow, magenta, white and black. 12 | """ 13 | red = (0, 0, 255) 14 | green = (0, 255, 0) 15 | blue = (255, 0, 0) 16 | cyan = (255, 255, 0) 17 | yellow = (0, 255, 255) 18 | magenta = (255, 0, 255) 19 | white = (255, 255, 255) 20 | black = (0, 0, 0) 21 | 22 | 23 | def color_val(color): 24 | """Convert various input to color tuples. 25 | 26 | Args: 27 | color (:obj:`Color`/str/tuple/int/ndarray): Color inputs 28 | 29 | Returns: 30 | tuple[int]: A tuple of 3 integers indicating BGR channels. 31 | """ 32 | if is_str(color): 33 | return Color[color].value 34 | elif isinstance(color, Color): 35 | return color.value 36 | elif isinstance(color, tuple): 37 | assert len(color) == 3 38 | for channel in color: 39 | assert channel >= 0 and channel <= 255 40 | return color 41 | elif isinstance(color, int): 42 | assert color >= 0 and color <= 255 43 | return color, color, color 44 | elif isinstance(color, np.ndarray): 45 | assert color.ndim == 1 and color.size == 3 46 | assert np.all((color >= 0) & (color <= 255)) 47 | color = color.astype(np.uint8) 48 | return tuple(color) 49 | else: 50 | raise TypeError('Invalid type for color: {}'.format(type(color))) 51 | -------------------------------------------------------------------------------- /mmcv/requirements.txt: -------------------------------------------------------------------------------- 1 | addict 2 | numpy>=1.11.1 3 | pyyaml 4 | six 5 | requests 6 | opencv-python 7 | -------------------------------------------------------------------------------- /mmcv/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | 4 | [aliases] 5 | test=pytest 6 | 7 | [tool:pytest] 8 | addopts=tests/ -------------------------------------------------------------------------------- /mmcv/setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from io import open # for Python 2 (identical to builtin in Python 3) 3 | 4 | from setuptools import Extension, find_packages, setup 5 | 6 | import numpy 7 | from Cython.Distutils import build_ext 8 | 9 | install_requires = [ 10 | 'numpy>=1.11.1', 'pyyaml', 'six', 'addict', 'requests', 'opencv-python', 11 | 'Cython' 12 | ] 13 | if sys.version_info < (3, 3): 14 | install_requires.append('backports.shutil_get_terminal_size') 15 | if sys.version_info < (3, 4): 16 | install_requires.extend(['enum34', 'pathlib']) 17 | 18 | 19 | def readme(): 20 | with open('README.rst', encoding='utf-8') as f: 21 | content = f.read() 22 | return content 23 | 24 | 25 | def get_version(): 26 | version_file = 'mmcv/version.py' 27 | with open(version_file, 'r', encoding='utf-8') as f: 28 | exec(compile(f.read(), version_file, 'exec')) 29 | return locals()['__version__'] 30 | 31 | 32 | EXT_MODULES = [ 33 | Extension( 34 | name='mmcv._ext', 35 | sources=[ 36 | './mmcv/video/optflow_warp/flow_warp.cpp', 37 | './mmcv/video/optflow_warp/flow_warp_module.pyx' 38 | ], 39 | include_dirs=[numpy.get_include()], 40 | language="c++", 41 | ), 42 | ] 43 | 44 | setup( 45 | name='mmcv', 46 | version=get_version(), 47 | description='Open MMLab Computer Vision Foundation', 48 | long_description=readme(), 49 | keywords='computer vision', 50 | packages=find_packages(), 51 | classifiers=[ 52 | 'Development Status :: 4 - Beta', 53 | 'License :: OSI Approved :: Apache Software License', 54 | 'Operating System :: OS Independent', 55 | 'Programming Language :: Python :: 2', 56 | 'Programming Language :: Python :: 2.7', 57 | 'Programming Language :: Python :: 3', 58 | 'Programming Language :: Python :: 3.4', 59 | 'Programming Language :: Python :: 3.5', 60 | 'Programming Language :: Python :: 3.6', 61 | 'Programming Language :: Python :: 3.7', 62 | 'Topic :: Utilities', 63 | ], 64 | url='https://github.com/open-mmlab/mmcv', 65 | author='Kai Chen', 66 | author_email='chenkaidev@gmail.com', 67 | setup_requires=['pytest-runner'], 68 | tests_require=['pytest'], 69 | install_requires=install_requires, 70 | ext_modules=EXT_MODULES, 71 | cmdclass={'build_ext': build_ext}, 72 | zip_safe=False) 73 | -------------------------------------------------------------------------------- /mmcv/tests/test_path.py: -------------------------------------------------------------------------------- 1 | import os.path as osp 2 | import sys 3 | from pathlib import Path 4 | 5 | import mmcv 6 | import pytest 7 | 8 | 9 | def test_is_filepath(): 10 | assert mmcv.is_filepath(__file__) 11 | assert mmcv.is_filepath('abc') 12 | assert mmcv.is_filepath(Path('/etc')) 13 | assert not mmcv.is_filepath(0) 14 | 15 | 16 | def test_fopen(): 17 | assert hasattr(mmcv.fopen(__file__), 'read') 18 | assert hasattr(mmcv.fopen(Path(__file__)), 'read') 19 | 20 | 21 | def test_check_file_exist(): 22 | mmcv.check_file_exist(__file__) 23 | if sys.version_info > (3, 3): 24 | with pytest.raises(FileNotFoundError): # noqa 25 | mmcv.check_file_exist('no_such_file.txt') 26 | else: 27 | with pytest.raises(IOError): 28 | mmcv.check_file_exist('no_such_file.txt') 29 | 30 | 31 | def test_scandir(): 32 | folder = osp.join(osp.dirname(__file__), 'data/for_scan') 33 | filenames = ['a.bin', '1.txt', '2.txt', '1.json', '2.json'] 34 | 35 | assert set(mmcv.scandir(folder)) == set(filenames) 36 | assert set(mmcv.scandir(folder, '.txt')) == set( 37 | [filename for filename in filenames if filename.endswith('.txt')]) 38 | assert set(mmcv.scandir(folder, ('.json', '.txt'))) == set([ 39 | filename for filename in filenames 40 | if filename.endswith(('.txt', '.json')) 41 | ]) 42 | assert set(mmcv.scandir(folder, '.png')) == set() 43 | with pytest.raises(TypeError): 44 | mmcv.scandir(folder, 111) 45 | -------------------------------------------------------------------------------- /mmcv/tests/test_runner.py: -------------------------------------------------------------------------------- 1 | import os.path as osp 2 | import tempfile 3 | import warnings 4 | 5 | 6 | def test_save_checkpoint(): 7 | try: 8 | import torch 9 | import torch.nn as nn 10 | except ImportError: 11 | warnings.warn('Skipping test_save_checkpoint in the absense of torch') 12 | return 13 | 14 | import mmcv.runner 15 | 16 | model = nn.Linear(1, 1) 17 | runner = mmcv.runner.Runner( 18 | model=model, 19 | batch_processor=lambda x: x 20 | ) 21 | 22 | with tempfile.TemporaryDirectory() as root: 23 | runner.save_checkpoint(root) 24 | 25 | latest_path = osp.join(root, 'latest.pth') 26 | epoch1_path = osp.join(root, 'epoch_1.pth') 27 | 28 | assert osp.exists(latest_path) 29 | assert osp.exists(epoch1_path) 30 | assert osp.realpath(latest_path) == epoch1_path 31 | 32 | torch.load(latest_path) 33 | -------------------------------------------------------------------------------- /mmcv/tests/test_timer.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import mmcv 4 | import pytest 5 | 6 | 7 | def test_timer_init(): 8 | timer = mmcv.Timer(start=False) 9 | assert not timer.is_running 10 | timer.start() 11 | assert timer.is_running 12 | timer = mmcv.Timer() 13 | assert timer.is_running 14 | 15 | 16 | def test_timer_run(): 17 | timer = mmcv.Timer() 18 | time.sleep(1) 19 | assert abs(timer.since_start() - 1) < 1e-2 20 | time.sleep(1) 21 | assert abs(timer.since_last_check() - 1) < 1e-2 22 | assert abs(timer.since_start() - 2) < 1e-2 23 | timer = mmcv.Timer(False) 24 | with pytest.raises(mmcv.TimerError): 25 | timer.since_start() 26 | with pytest.raises(mmcv.TimerError): 27 | timer.since_last_check() 28 | 29 | 30 | def test_timer_context(capsys): 31 | with mmcv.Timer(): 32 | time.sleep(1) 33 | out, _ = capsys.readouterr() 34 | assert abs(float(out) - 1) < 1e-2 35 | with mmcv.Timer(print_tmpl='time: {:.1f}s'): 36 | time.sleep(1) 37 | out, _ = capsys.readouterr() 38 | assert out == 'time: 1.0s\n' 39 | -------------------------------------------------------------------------------- /mmcv/tests/test_visualization.py: -------------------------------------------------------------------------------- 1 | import mmcv 2 | import numpy as np 3 | import pytest 4 | 5 | 6 | def test_color(): 7 | assert mmcv.color_val(mmcv.Color.blue) == (255, 0, 0) 8 | assert mmcv.color_val('green') == (0, 255, 0) 9 | assert mmcv.color_val((1, 2, 3)) == (1, 2, 3) 10 | assert mmcv.color_val(100) == (100, 100, 100) 11 | assert mmcv.color_val(np.zeros(3, dtype=np.int)) == (0, 0, 0) 12 | with pytest.raises(TypeError): 13 | mmcv.color_val([255, 255, 255]) 14 | with pytest.raises(TypeError): 15 | mmcv.color_val(1.0) 16 | with pytest.raises(AssertionError): 17 | mmcv.color_val((0, 0, 500)) 18 | -------------------------------------------------------------------------------- /mmdetection/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to mmdetection 2 | 3 | All kinds of contributions are welcome, including but not limited to the following. 4 | 5 | - Fixes (typo, bugs) 6 | - New features and components 7 | 8 | ## Workflow 9 | 10 | 1. fork and pull the latest mmdetection 11 | 2. checkout a new branch (do not use master branch for PRs) 12 | 3. commit your changes 13 | 4. create a PR 14 | 15 | Note 16 | - If you plan to add some new features that involve large changes, it is encouraged to open an issue for discussion first. 17 | - If you are the author of some papers and would like to include your method to mmdetection, 18 | please contact Kai Chen (chenkaidev[at]gmail[dot]com). We will much appreciate your contribution. 19 | 20 | ## Code style 21 | 22 | ### Python 23 | We adopt [PEP8](https://www.python.org/dev/peps/pep-0008/) as the preferred code style. 24 | We use [flake8](http://flake8.pycqa.org/en/latest/) as the linter and [yapf](https://github.com/google/yapf) as the formatter. 25 | Please upgrade to the latest yapf (>=0.27.0) and refer to the [configuration](.style.yapf). 26 | 27 | >Before you create a PR, make sure that your code lints and is formatted by yapf. 28 | 29 | ### C++ and CUDA 30 | We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). -------------------------------------------------------------------------------- /mmdetection/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/__init__.py -------------------------------------------------------------------------------- /mmdetection/compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PYTHON=${PYTHON:-"python3"} 4 | 5 | echo "Building roi align op..." 6 | cd mmdet/ops/roi_align 7 | if [ -d "build" ]; then 8 | rm -r build 9 | fi 10 | $PYTHON setup.py build_ext --inplace 11 | 12 | echo "Building roi pool op..." 13 | cd ../roi_pool 14 | if [ -d "build" ]; then 15 | rm -r build 16 | fi 17 | $PYTHON setup.py build_ext --inplace 18 | 19 | echo "Building nms op..." 20 | cd ../nms 21 | if [ -d "build" ]; then 22 | rm -r build 23 | fi 24 | $PYTHON setup.py build_ext --inplace 25 | 26 | # echo "Building kpts nms op..." 27 | # cd ../kpts_nms 28 | # if [ -d "build" ]; then 29 | # rm -r build 30 | # fi 31 | # $PYTHON setup.py build_ext --inplace 32 | 33 | echo "Building dcn..." 34 | cd ../dcn 35 | if [ -d "build" ]; then 36 | rm -r build 37 | fi 38 | $PYTHON setup.py build_ext --inplace 39 | 40 | echo "Building sigmoid focal loss op..." 41 | cd ../sigmoid_focal_loss 42 | if [ -d "build" ]; then 43 | rm -r build 44 | fi 45 | $PYTHON setup.py build_ext --inplace 46 | 47 | echo "Building masked conv op..." 48 | cd ../masked_conv 49 | if [ -d "build" ]; then 50 | rm -r build 51 | fi 52 | $PYTHON setup.py build_ext --inplace 53 | -------------------------------------------------------------------------------- /mmdetection/configs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/configs/__init__.py -------------------------------------------------------------------------------- /mmdetection/configs/empirical_attention/README.md: -------------------------------------------------------------------------------- 1 | # An Empirical Study of Spatial Attention Mechanisms in Deep Networks 2 | 3 | ## Introduction 4 | 5 | ``` 6 | @article{zhu2019empirical, 7 | title={An Empirical Study of Spatial Attention Mechanisms in Deep Networks}, 8 | author={Zhu, Xizhou and Cheng, Dazhi and Zhang, Zheng and Lin, Stephen and Dai, Jifeng}, 9 | journal={arXiv preprint arXiv:1904.05873}, 10 | year={2019} 11 | } 12 | ``` 13 | 14 | 15 | ## Results and Models 16 | 17 | | Backbone | Attention Component | DCN | Lr schd | box AP | Download | 18 | |:---------:|:-------------------:|:----:|:-------:|:------:|:--------:| 19 | | R-50 | 1111 | N | 1x | 38.6 | - | 20 | | R-50 | 0010 | N | 1x | 38.2 | - | 21 | | R-50 | 1111 | Y | 1x | 41.0 | - | 22 | | R-50 | 0010 | Y | 1x | 40.8 | - | 23 | 24 | -------------------------------------------------------------------------------- /mmdetection/configs/ghm/README.md: -------------------------------------------------------------------------------- 1 | # Gradient Harmonized Single-stage Detector 2 | 3 | ## Introduction 4 | 5 | ``` 6 | @inproceedings{li2019gradient, 7 | title={Gradient Harmonized Single-stage Detector}, 8 | author={Li, Buyu and Liu, Yu and Wang, Xiaogang}, 9 | booktitle={AAAI Conference on Artificial Intelligence}, 10 | year={2019} 11 | } 12 | ``` 13 | 14 | ## Results and Models 15 | 16 | | Backbone | Style | Lr schd | Mem (GB) | Train time (s/iter) | Inf time (fps) | box AP | Download | 17 | | :-------------: | :-----: | :-----: | :------: | :-----------------: | :------------: | :----: | :------: | 18 | | R-50-FPN | pytorch | 1x | 3.9 | 0.500 | 9.4 | 36.9 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ghm/retinanet_ghm_r50_fpn_1x_20190608-b9aa5862.pth) | 19 | | R-101-FPN | pytorch | 1x | 5.8 | 0.625 | 8.5 | 39.0 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ghm/retinanet_ghm_r101_fpn_1x_20190608-b885b74a.pth) | 20 | | X-101-32x4d-FPN | pytorch | 1x | 7.0 | 0.818 | 7.6 | 40.5 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ghm/retinanet_ghm_x101_32x4d_fpn_1x_20190608-ed295d22.pth) | 21 | | X-101-64x4d-FPN | pytorch | 1x | 9.9 | 1.191 | 6.1 | 41.6 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ghm/retinanet_ghm_x101_64x4d_fpn_1x_20190608-7f2037ce.pth) | -------------------------------------------------------------------------------- /mmdetection/configs/gn/README.md: -------------------------------------------------------------------------------- 1 | # Group Normalization 2 | 3 | ## Introduction 4 | 5 | ``` 6 | @inproceedings{wu2018group, 7 | title={Group Normalization}, 8 | author={Wu, Yuxin and He, Kaiming}, 9 | booktitle={Proceedings of the European Conference on Computer Vision (ECCV)}, 10 | year={2018} 11 | } 12 | ``` 13 | 14 | ## Results and Models 15 | 16 | | Backbone | model | Lr schd | Mem (GB) | Train time (s/iter) | Inf time (fps) | box AP | mask AP | Download | 17 | |:-------------:|:----------:|:-------:|:--------:|:-------------------:|:--------------:|:------:|:-------:|:--------:| 18 | | R-50-FPN (d) | Mask R-CNN | 2x | 7.2 | 0.806 | 5.4 | 39.8 | 36.1 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/gn/mask_rcnn_r50_fpn_gn_2x_20180113-86832cf2.pth) | 19 | | R-50-FPN (d) | Mask R-CNN | 3x | 7.2 | 0.806 | 5.4 | 40.1 | 36.4 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/gn/mask_rcnn_r50_fpn_gn_3x_20180113-8e82f48d.pth) | 20 | | R-101-FPN (d) | Mask R-CNN | 2x | 9.9 | 0.970 | 4.8 | 41.5 | 37.0 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/gn/mask_rcnn_r101_fpn_gn_2x_20180113-9598649c.pth) | 21 | | R-101-FPN (d) | Mask R-CNN | 3x | 9.9 | 0.970 | 4.8 | 41.6 | 37.3 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/gn/mask_rcnn_r101_fpn_gn_3x_20180113-a14ffb96.pth) | 22 | | R-50-FPN (c) | Mask R-CNN | 2x | 7.2 | 0.806 | 5.4 | 39.7 | 35.9 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/gn/mask_rcnn_r50_fpn_gn_contrib_2x_20180113-ec93305c.pth) | 23 | | R-50-FPN (c) | Mask R-CNN | 3x | 7.2 | 0.806 | 5.4 | 40.0 | 36.2 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/gn/mask_rcnn_r50_fpn_gn_contrib_3x_20180113-9d230cab.pth) | 24 | 25 | **Notes:** 26 | - (d) means pretrained model converted from Detectron, and (c) means the contributed model pretrained by [@thangvubk](https://github.com/thangvubk). 27 | - The `3x` schedule is epoch [28, 34, 36]. 28 | - **Memory, Train/Inf time is outdated.** -------------------------------------------------------------------------------- /mmdetection/configs/grid_rcnn/README.md: -------------------------------------------------------------------------------- 1 | # Grid R-CNN 2 | 3 | ## Introduction 4 | 5 | ``` 6 | @inproceedings{lu2019grid, 7 | title={Grid r-cnn}, 8 | author={Lu, Xin and Li, Buyu and Yue, Yuxin and Li, Quanquan and Yan, Junjie}, 9 | booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition}, 10 | year={2019} 11 | } 12 | 13 | @article{lu2019grid, 14 | title={Grid R-CNN Plus: Faster and Better}, 15 | author={Lu, Xin and Li, Buyu and Yue, Yuxin and Li, Quanquan and Yan, Junjie}, 16 | journal={arXiv preprint arXiv:1906.05688}, 17 | year={2019} 18 | } 19 | ``` 20 | 21 | ## Results and Models 22 | 23 | | Backbone | Lr schd | Mem (GB) | Train time (s/iter) | Inf time (fps) | box AP | Download | 24 | |:-----------:|:-------:|:--------:|:-------------------:|:--------------:|:------:|:--------:| 25 | | R-50 | 2x | 4.8 | 1.172 | 10.9 | 40.3 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/grid_rcnn/grid_rcnn_gn_head_r50_fpn_2x_20190619-5b29cf9d.pth) | 26 | | R-101 | 2x | 6.7 | 1.214 | 10.0 | 41.7 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/grid_rcnn/grid_rcnn_gn_head_r101_fpn_2x_20190619-a4b61645.pth) | 27 | | X-101-32x4d | 2x | 8.0 | 1.335 | 8.5 | 43.0 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/grid_rcnn/grid_rcnn_gn_head_x101_32x4d_fpn_2x_20190619-0bbfd87a.pth) | 28 | | X-101-64x4d | 2x | 10.9 | 1.753 | 6.4 | 43.1 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/grid_rcnn/grid_rcnn_gn_head_x101_64x4d_fpn_2x_20190619-8f4e20bb.pth) | 29 | 30 | **Notes:** 31 | - All models are trained with 8 GPUs instead of 32 GPUs in the original paper. 32 | - The warming up lasts for 1 epoch and `2x` here indicates 25 epochs. 33 | -------------------------------------------------------------------------------- /mmdetection/configs/libra_rcnn/README.md: -------------------------------------------------------------------------------- 1 | # Libra R-CNN: Towards Balanced Learning for Object Detection 2 | 3 | ## Introduction 4 | 5 | We provide config files to reproduce the results in the CVPR 2019 paper [Libra R-CNN](https://arxiv.org/pdf/1904.02701.pdf). 6 | 7 | ``` 8 | @inproceedings{pang2019libra, 9 | title={Libra R-CNN: Towards Balanced Learning for Object Detection}, 10 | author={Pang, Jiangmiao and Chen, Kai and Shi, Jianping and Feng, Huajun and Ouyang, Wanli and Dahua Lin}, 11 | booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, 12 | year={2019} 13 | } 14 | ``` 15 | 16 | ## Results and models 17 | 18 | The results on COCO 2017val are shown in the below table. (results on test-dev are usually slightly higher than val) 19 | 20 | | Architecture | Backbone | Style | Lr schd | Mem (GB) | Train time (s/iter) | Inf time (fps) | box AP | Download | 21 | |:---------:|:-------:|:-------:|:--------:|:-------------------:|:--------------:|:------:|:-------:|:--------:| 22 | | Faster R-CNN | R-50-FPN | pytorch | 1x | 4.2 | 0.375 | 12.0 | 38.5 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/libra_rcnn/libra_faster_rcnn_r50_fpn_1x_20190610-bf0ea559.pth) | 23 | | Fast R-CNN | R-50-FPN | pytorch | 1x | 3.7 | 0.272 | 16.3 | 38.5 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/libra_rcnn/libra_fast_rcnn_r50_fpn_1x_20190525-a43f88b5.pth) | 24 | | Faster R-CNN | R-101-FPN | pytorch | 1x | 6.0 | 0.495 | 10.4 | 40.3 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/libra_rcnn/libra_faster_rcnn_r101_fpn_1x_20190525-94e94051.pth) | 25 | | Faster R-CNN | X-101-64x4d-FPN | pytorch | 1x | 10.1 | 1.050 | 6.8 | 42.7 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/libra_rcnn/libra_faster_rcnn_x101_64x4d_fpn_1x_20190525-359c134a.pth) | 26 | | RetinaNet | R-50-FPN | pytorch | 1x | 3.7 | 0.328 | 11.8 | 37.7 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/libra_rcnn/libra_retinanet_r50_fpn_1x_20190525-ead2a6bb.pth) | 27 | -------------------------------------------------------------------------------- /mmdetection/configs/ms_rcnn/README.md: -------------------------------------------------------------------------------- 1 | # Mask Scoring R-CNN 2 | 3 | ## Introduction 4 | 5 | ``` 6 | @inproceedings{huang2019msrcnn, 7 | title={Mask Scoring R-CNN}, 8 | author={Zhaojin Huang and Lichao Huang and Yongchao Gong and Chang Huang and Xinggang Wang}, 9 | booktitle={IEEE Conference on Computer Vision and Pattern Recognition}, 10 | year={2019}, 11 | } 12 | ``` 13 | 14 | ## Results and Models 15 | 16 | | Backbone | style | Lr schd | Mem (GB) | Train time (s/iter) | Inf time (fps) | box AP | mask AP | Download | 17 | |:-------------:|:----------:|:-------:|:--------:|:-------------------:|:--------------:|:------:|:-------:|:--------:| 18 | | R-50-FPN | caffe | 1x | 4.3 | 0.537 | 10.1 | 37.4 | 35.5 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ms-rcnn/ms_rcnn_r50_caffe_fpn_1x_20190624-619934b5.pth) | 19 | | R-50-FPN | caffe | 2x | - | - | - | 38.2 | 35.9 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/ms-rcnn/ms_rcnn_r50_caffe_fpn_2x_20190525-a07be31e.pth) | 20 | | R-101-FPN | caffe | 1x | 6.2 | 0.682 | 9.1 | 39.8 | 37.2 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ms-rcnn/ms_rcnn_r101_caffe_fpn_1x_20190624-677a5548.pth) | 21 | | R-101-FPN | caffe | 2x | - | - | - | 40.7 | 37.8 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/ms-rcnn/ms_rcnn_r101_caffe_fpn_2x_20190525-4aee1528.pth) | 22 | | R-X101-32x4d | pytorch | 2x | 7.6 | 0.844 | 8.0 | 41.7 | 38.5 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ms-rcnn/ms_rcnn_x101_32x4d_fpn_2x_20190628-ab454d07.pth) | 23 | | R-X101-64x4d | pytorch | 1x | 10.5 | 1.214 | 6.4 | 42.0 | 39.1 | [model](https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/models/ms-rcnn/ms_rcnn_x101_64x4d_fpn_1x_20190628-dec32bda.pth) | 24 | | R-X101-64x4d | pytorch | 2x | - | - | - | 42.2 | 38.9 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/ms-rcnn/ms_rcnn_x101_64x4d_fpn_2x_20190525-c044c25a.pth) | 25 | -------------------------------------------------------------------------------- /mmdetection/configs/scratch/README.md: -------------------------------------------------------------------------------- 1 | # Rethinking ImageNet Pre-training 2 | 3 | ## Introduction 4 | 5 | ``` 6 | @article{he2018rethinking, 7 | title={Rethinking imagenet pre-training}, 8 | author={He, Kaiming and Girshick, Ross and Doll{\'a}r, Piotr}, 9 | journal={arXiv preprint arXiv:1811.08883}, 10 | year={2018} 11 | } 12 | ``` 13 | 14 | ## Results and Models 15 | 16 | | Model | Backbone | Style | Lr schd | box AP | mask AP | Download | 17 | |:------------:|:---------:|:-------:|:-------:|:------:|:-------:|:--------:| 18 | | Faster R-CNN | R-50-FPN | pytorch | 6x | 40.1 | - | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/scratch/scratch_faster_rcnn_r50_fpn_gn_6x-20190515-ff554978.pth) | 19 | | Mask R-CNN | R-50-FPN | pytorch | 6x | 41.0 | 37.4 | [model](https://s3.ap-northeast-2.amazonaws.com/open-mmlab/mmdetection/models/scratch/scratch_mask_rcnn_r50_fpn_gn_6x_20190515-96743f5e.pth) | 20 | 21 | Note: 22 | - The above models are trained with 16 GPUs. -------------------------------------------------------------------------------- /mmdetection/configs/wider_face/README.md: -------------------------------------------------------------------------------- 1 | ## WIDER Face Dataset 2 | 3 | To use the WIDER Face dataset you need to download it 4 | and extract to the `data/WIDERFace` folder. Annotation in the VOC format 5 | can be found in this [repo](https://github.com/sovrasov/wider-face-pascal-voc-annotations.git). 6 | You should move the annotation files from `WIDER_train_annotations` and `WIDER_val_annotations` folders 7 | to the `Annotation` folders inside the corresponding directories `WIDER_train` and `WIDER_val`. 8 | Also annotation lists `val.txt` and `train.txt` should be copied to `data/WIDERFace` from `WIDER_train_annotations` and `WIDER_val_annotations`. 9 | The directory should be like this: 10 | 11 | ``` 12 | mmdetection 13 | ├── mmdet 14 | ├── tools 15 | ├── configs 16 | ├── data 17 | │ ├── WIDERFace 18 | │ │ ├── WIDER_train 19 | │ | │ ├──0--Parade 20 | │ | │ ├── ... 21 | │ | │ ├── Annotations 22 | │ │ ├── WIDER_val 23 | │ | │ ├──0--Parade 24 | │ | │ ├── ... 25 | │ | │ ├── Annotations 26 | │ │ ├── val.txt 27 | │ │ ├── train.txt 28 | 29 | ``` 30 | 31 | After that you can train the SSD300 on WIDER by launching training with the `ssd300_wider_face.py` config or 32 | create your own config based on the presented one. 33 | -------------------------------------------------------------------------------- /mmdetection/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /mmdetection/demo_images/001289747.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/demo_images/001289747.jpg -------------------------------------------------------------------------------- /mmdetection/mmdet/__init__.py: -------------------------------------------------------------------------------- 1 | from .version import __version__, short_version 2 | 3 | __all__ = ['__version__', 'short_version'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/apis/__init__.py: -------------------------------------------------------------------------------- 1 | from .env import init_dist, get_root_logger, set_random_seed 2 | from .train import train_detector, train_smpl_detector_fuse, \ 3 | train_adv_smpl_detector 4 | from .inference import init_detector, inference_detector, show_result 5 | 6 | __all__ = [ 7 | 'init_dist', 'get_root_logger', 'set_random_seed', 'train_detector', 8 | 'init_detector', 'inference_detector', 'show_result', 'train_smpl_detector_fuse', 9 | 'train_adv_smpl_detector' 10 | ] 11 | -------------------------------------------------------------------------------- /mmdetection/mmdet/apis/env.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import random 4 | import subprocess 5 | 6 | import numpy as np 7 | import torch 8 | import torch.distributed as dist 9 | import torch.multiprocessing as mp 10 | from mmcv.runner import get_dist_info 11 | 12 | 13 | def init_dist(launcher, backend='nccl', **kwargs): 14 | if mp.get_start_method(allow_none=True) is None: 15 | mp.set_start_method('spawn') 16 | if launcher == 'pytorch': 17 | _init_dist_pytorch(backend, **kwargs) 18 | elif launcher == 'mpi': 19 | _init_dist_mpi(backend, **kwargs) 20 | elif launcher == 'slurm': 21 | _init_dist_slurm(backend, **kwargs) 22 | else: 23 | raise ValueError('Invalid launcher type: {}'.format(launcher)) 24 | 25 | 26 | def _init_dist_pytorch(backend, **kwargs): 27 | # TODO: use local_rank instead of rank % num_gpus 28 | rank = int(os.environ['RANK']) 29 | num_gpus = torch.cuda.device_count() 30 | torch.cuda.set_device(rank % num_gpus) 31 | dist.init_process_group(backend=backend, **kwargs) 32 | 33 | 34 | def _init_dist_mpi(backend, **kwargs): 35 | raise NotImplementedError 36 | 37 | 38 | def _init_dist_slurm(backend, port=29500, **kwargs): 39 | proc_id = int(os.environ['SLURM_PROCID']) 40 | ntasks = int(os.environ['SLURM_NTASKS']) 41 | node_list = os.environ['SLURM_NODELIST'] 42 | num_gpus = torch.cuda.device_count() 43 | torch.cuda.set_device(proc_id % num_gpus) 44 | addr = subprocess.getoutput( 45 | 'scontrol show hostname {} | head -n1'.format(node_list)) 46 | os.environ['MASTER_PORT'] = str(port) 47 | os.environ['MASTER_ADDR'] = addr 48 | os.environ['WORLD_SIZE'] = str(ntasks) 49 | os.environ['RANK'] = str(proc_id) 50 | dist.init_process_group(backend=backend) 51 | 52 | 53 | def set_random_seed(seed): 54 | random.seed(seed) 55 | np.random.seed(seed) 56 | torch.manual_seed(seed) 57 | torch.cuda.manual_seed_all(seed) 58 | 59 | 60 | def get_root_logger(log_level=logging.INFO): 61 | logger = logging.getLogger() 62 | if not logger.hasHandlers(): 63 | logging.basicConfig( 64 | format='%(asctime)s - %(levelname)s - %(message)s', 65 | level=log_level) 66 | rank, _ = get_dist_info() 67 | if rank != 0: 68 | logger.setLevel('ERROR') 69 | return logger 70 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/__init__.py: -------------------------------------------------------------------------------- 1 | from .anchor import * # noqa: F401, F403 2 | from .bbox import * # noqa: F401, F403 3 | from .evaluation import * # noqa: F401, F403 4 | from .fp16 import * # noqa: F401, F403 5 | from .mask import * # noqa: F401, F403 6 | from .post_processing import * # noqa: F401, F403 7 | from .utils import * # noqa: F401, F403 8 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/anchor/__init__.py: -------------------------------------------------------------------------------- 1 | from .anchor_generator import AnchorGenerator 2 | from .anchor_target import anchor_target, anchor_inside_flags 3 | from .guided_anchor_target import ga_loc_target, ga_shape_target 4 | 5 | __all__ = [ 6 | 'AnchorGenerator', 'anchor_target', 'anchor_inside_flags', 'ga_loc_target', 7 | 'ga_shape_target' 8 | ] 9 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/__init__.py: -------------------------------------------------------------------------------- 1 | from .geometry import bbox_overlaps 2 | from .assigners import BaseAssigner, MaxIoUAssigner, AssignResult 3 | from .samplers import (BaseSampler, PseudoSampler, RandomSampler, 4 | InstanceBalancedPosSampler, IoUBalancedNegSampler, 5 | CombinedSampler, SamplingResult) 6 | from .assign_sampling import build_assigner, build_sampler, assign_and_sample 7 | from .transforms import (bbox2delta, delta2bbox, bbox_flip, bbox_mapping, 8 | bbox_mapping_back, bbox2roi, roi2bbox, bbox2result, 9 | distance2bbox) 10 | from .bbox_target import bbox_target 11 | 12 | __all__ = [ 13 | 'bbox_overlaps', 'BaseAssigner', 'MaxIoUAssigner', 'AssignResult', 14 | 'BaseSampler', 'PseudoSampler', 'RandomSampler', 15 | 'InstanceBalancedPosSampler', 'IoUBalancedNegSampler', 'CombinedSampler', 16 | 'SamplingResult', 'build_assigner', 'build_sampler', 'assign_and_sample', 17 | 'bbox2delta', 'delta2bbox', 'bbox_flip', 'bbox_mapping', 18 | 'bbox_mapping_back', 'bbox2roi', 'roi2bbox', 'bbox2result', 19 | 'distance2bbox', 'bbox_target' 20 | ] 21 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/assign_sampling.py: -------------------------------------------------------------------------------- 1 | import mmcv 2 | 3 | from . import assigners, samplers 4 | 5 | 6 | def build_assigner(cfg, **kwargs): 7 | if isinstance(cfg, assigners.BaseAssigner): 8 | return cfg 9 | elif isinstance(cfg, dict): 10 | return mmcv.runner.obj_from_dict(cfg, assigners, default_args=kwargs) 11 | else: 12 | raise TypeError('Invalid type {} for building a sampler'.format( 13 | type(cfg))) 14 | 15 | 16 | def build_sampler(cfg, **kwargs): 17 | if isinstance(cfg, samplers.BaseSampler): 18 | return cfg 19 | elif isinstance(cfg, dict): 20 | return mmcv.runner.obj_from_dict(cfg, samplers, default_args=kwargs) 21 | else: 22 | raise TypeError('Invalid type {} for building a sampler'.format( 23 | type(cfg))) 24 | 25 | 26 | def assign_and_sample(bboxes, gt_bboxes, gt_bboxes_ignore, gt_labels, cfg): 27 | bbox_assigner = build_assigner(cfg.assigner) 28 | bbox_sampler = build_sampler(cfg.sampler) 29 | assign_result = bbox_assigner.assign(bboxes, gt_bboxes, gt_bboxes_ignore, 30 | gt_labels) 31 | sampling_result = bbox_sampler.sample(assign_result, bboxes, gt_bboxes, 32 | gt_labels) 33 | return assign_result, sampling_result 34 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/assigners/__init__.py: -------------------------------------------------------------------------------- 1 | from .base_assigner import BaseAssigner 2 | from .max_iou_assigner import MaxIoUAssigner 3 | from .approx_max_iou_assigner import ApproxMaxIoUAssigner 4 | from .assign_result import AssignResult 5 | 6 | __all__ = [ 7 | 'BaseAssigner', 'MaxIoUAssigner', 'ApproxMaxIoUAssigner', 'AssignResult' 8 | ] 9 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/assigners/assign_result.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class AssignResult(object): 5 | 6 | def __init__(self, num_gts, gt_inds, max_overlaps, labels=None): 7 | self.num_gts = num_gts 8 | self.gt_inds = gt_inds 9 | self.max_overlaps = max_overlaps 10 | self.labels = labels 11 | 12 | def add_gt_(self, gt_labels): 13 | self_inds = torch.arange( 14 | 1, len(gt_labels) + 1, dtype=torch.long, device=gt_labels.device) 15 | self.gt_inds = torch.cat([self_inds, self.gt_inds]) 16 | self.max_overlaps = torch.cat( 17 | [self.max_overlaps.new_ones(self.num_gts), self.max_overlaps]) 18 | if self.labels is not None: 19 | self.labels = torch.cat([gt_labels, self.labels]) 20 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/assigners/base_assigner.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | 4 | class BaseAssigner(metaclass=ABCMeta): 5 | 6 | @abstractmethod 7 | def assign(self, bboxes, gt_bboxes, gt_bboxes_ignore=None, gt_labels=None): 8 | pass 9 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/samplers/__init__.py: -------------------------------------------------------------------------------- 1 | from .base_sampler import BaseSampler 2 | from .pseudo_sampler import PseudoSampler 3 | from .random_sampler import RandomSampler 4 | from .instance_balanced_pos_sampler import InstanceBalancedPosSampler 5 | from .iou_balanced_neg_sampler import IoUBalancedNegSampler 6 | from .combined_sampler import CombinedSampler 7 | from .ohem_sampler import OHEMSampler 8 | from .sampling_result import SamplingResult 9 | 10 | __all__ = [ 11 | 'BaseSampler', 'PseudoSampler', 'RandomSampler', 12 | 'InstanceBalancedPosSampler', 'IoUBalancedNegSampler', 'CombinedSampler', 13 | 'OHEMSampler', 'SamplingResult' 14 | ] 15 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/samplers/combined_sampler.py: -------------------------------------------------------------------------------- 1 | from .base_sampler import BaseSampler 2 | from ..assign_sampling import build_sampler 3 | 4 | 5 | class CombinedSampler(BaseSampler): 6 | 7 | def __init__(self, pos_sampler, neg_sampler, **kwargs): 8 | super(CombinedSampler, self).__init__(**kwargs) 9 | self.pos_sampler = build_sampler(pos_sampler, **kwargs) 10 | self.neg_sampler = build_sampler(neg_sampler, **kwargs) 11 | 12 | def _sample_pos(self, **kwargs): 13 | raise NotImplementedError 14 | 15 | def _sample_neg(self, **kwargs): 16 | raise NotImplementedError 17 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/samplers/instance_balanced_pos_sampler.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | 4 | from .random_sampler import RandomSampler 5 | 6 | 7 | class InstanceBalancedPosSampler(RandomSampler): 8 | 9 | def _sample_pos(self, assign_result, num_expected, **kwargs): 10 | pos_inds = torch.nonzero(assign_result.gt_inds > 0) 11 | if pos_inds.numel() != 0: 12 | pos_inds = pos_inds.squeeze(1) 13 | if pos_inds.numel() <= num_expected: 14 | return pos_inds 15 | else: 16 | unique_gt_inds = assign_result.gt_inds[pos_inds].unique() 17 | num_gts = len(unique_gt_inds) 18 | num_per_gt = int(round(num_expected / float(num_gts)) + 1) 19 | sampled_inds = [] 20 | for i in unique_gt_inds: 21 | inds = torch.nonzero(assign_result.gt_inds == i.item()) 22 | if inds.numel() != 0: 23 | inds = inds.squeeze(1) 24 | else: 25 | continue 26 | if len(inds) > num_per_gt: 27 | inds = self.random_choice(inds, num_per_gt) 28 | sampled_inds.append(inds) 29 | sampled_inds = torch.cat(sampled_inds) 30 | if len(sampled_inds) < num_expected: 31 | num_extra = num_expected - len(sampled_inds) 32 | extra_inds = np.array( 33 | list(set(pos_inds.cpu()) - set(sampled_inds.cpu()))) 34 | if len(extra_inds) > num_extra: 35 | extra_inds = self.random_choice(extra_inds, num_extra) 36 | extra_inds = torch.from_numpy(extra_inds).to( 37 | assign_result.gt_inds.device).long() 38 | sampled_inds = torch.cat([sampled_inds, extra_inds]) 39 | elif len(sampled_inds) > num_expected: 40 | sampled_inds = self.random_choice(sampled_inds, num_expected) 41 | return sampled_inds 42 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/samplers/pseudo_sampler.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from .base_sampler import BaseSampler 4 | from .sampling_result import SamplingResult 5 | 6 | 7 | class PseudoSampler(BaseSampler): 8 | 9 | def __init__(self, **kwargs): 10 | pass 11 | 12 | def _sample_pos(self, **kwargs): 13 | raise NotImplementedError 14 | 15 | def _sample_neg(self, **kwargs): 16 | raise NotImplementedError 17 | 18 | def sample(self, assign_result, bboxes, gt_bboxes, **kwargs): 19 | pos_inds = torch.nonzero( 20 | assign_result.gt_inds > 0).squeeze(-1).unique() 21 | neg_inds = torch.nonzero( 22 | assign_result.gt_inds == 0).squeeze(-1).unique() 23 | gt_flags = bboxes.new_zeros(bboxes.shape[0], dtype=torch.uint8) 24 | sampling_result = SamplingResult(pos_inds, neg_inds, bboxes, gt_bboxes, 25 | assign_result, gt_flags) 26 | return sampling_result 27 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/samplers/random_sampler.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | 4 | from .base_sampler import BaseSampler 5 | 6 | 7 | class RandomSampler(BaseSampler): 8 | 9 | def __init__(self, 10 | num, 11 | pos_fraction, 12 | neg_pos_ub=-1, 13 | add_gt_as_proposals=True, 14 | **kwargs): 15 | super(RandomSampler, self).__init__(num, pos_fraction, neg_pos_ub, 16 | add_gt_as_proposals) 17 | 18 | @staticmethod 19 | def random_choice(gallery, num): 20 | """Random select some elements from the gallery. 21 | 22 | It seems that Pytorch's implementation is slower than numpy so we use 23 | numpy to randperm the indices. 24 | """ 25 | assert len(gallery) >= num 26 | if isinstance(gallery, list): 27 | gallery = np.array(gallery) 28 | cands = np.arange(len(gallery)) 29 | np.random.shuffle(cands) 30 | rand_inds = cands[:num] 31 | if not isinstance(gallery, np.ndarray): 32 | rand_inds = torch.from_numpy(rand_inds).long().to(gallery.device) 33 | return gallery[rand_inds] 34 | 35 | def _sample_pos(self, assign_result, num_expected, **kwargs): 36 | """Randomly sample some positive samples.""" 37 | pos_inds = torch.nonzero(assign_result.gt_inds > 0) 38 | if pos_inds.numel() != 0: 39 | pos_inds = pos_inds.squeeze(1) 40 | if pos_inds.numel() <= num_expected: 41 | return pos_inds 42 | else: 43 | return self.random_choice(pos_inds, num_expected) 44 | 45 | def _sample_neg(self, assign_result, num_expected, **kwargs): 46 | """Randomly sample some negative samples.""" 47 | neg_inds = torch.nonzero(assign_result.gt_inds == 0) 48 | if neg_inds.numel() != 0: 49 | neg_inds = neg_inds.squeeze(1) 50 | if len(neg_inds) <= num_expected: 51 | return neg_inds 52 | else: 53 | return self.random_choice(neg_inds, num_expected) 54 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/bbox/samplers/sampling_result.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class SamplingResult(object): 5 | 6 | def __init__(self, pos_inds, neg_inds, bboxes, gt_bboxes, assign_result, 7 | gt_flags): 8 | self.pos_inds = pos_inds 9 | self.neg_inds = neg_inds 10 | self.pos_bboxes = bboxes[pos_inds] 11 | self.neg_bboxes = bboxes[neg_inds] 12 | self.pos_is_gt = gt_flags[pos_inds] 13 | 14 | self.num_gts = gt_bboxes.shape[0] 15 | self.pos_assigned_gt_inds = assign_result.gt_inds[pos_inds] - 1 16 | self.pos_gt_bboxes = gt_bboxes[self.pos_assigned_gt_inds, :] 17 | if assign_result.labels is not None: 18 | self.pos_gt_labels = assign_result.labels[pos_inds] 19 | else: 20 | self.pos_gt_labels = None 21 | 22 | @property 23 | def bboxes(self): 24 | return torch.cat([self.pos_bboxes, self.neg_bboxes]) 25 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/evaluation/__init__.py: -------------------------------------------------------------------------------- 1 | from .class_names import (voc_classes, imagenet_det_classes, 2 | imagenet_vid_classes, coco_classes, dataset_aliases, 3 | get_classes) 4 | from .coco_utils import coco_eval, fast_eval_recall, results2json 5 | from .eval_hooks import (DistEvalHook, DistEvalmAPHook, CocoDistEvalRecallHook, 6 | CocoDistEvalmAPHook) 7 | from .mean_ap import average_precision, eval_map, print_map_summary 8 | from .recall import (eval_recalls, print_recall_summary, plot_num_recall, 9 | plot_iou_recall) 10 | 11 | __all__ = [ 12 | 'voc_classes', 'imagenet_det_classes', 'imagenet_vid_classes', 13 | 'coco_classes', 'dataset_aliases', 'get_classes', 'coco_eval', 14 | 'fast_eval_recall', 'results2json', 'DistEvalHook', 'DistEvalmAPHook', 15 | 'CocoDistEvalRecallHook', 'CocoDistEvalmAPHook', 'average_precision', 16 | 'eval_map', 'print_map_summary', 'eval_recalls', 'print_recall_summary', 17 | 'plot_num_recall', 'plot_iou_recall' 18 | ] 19 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/evaluation/bbox_overlaps.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def bbox_overlaps(bboxes1, bboxes2, mode='iou'): 5 | """Calculate the ious between each bbox of bboxes1 and bboxes2. 6 | 7 | Args: 8 | bboxes1(ndarray): shape (n, 4) 9 | bboxes2(ndarray): shape (k, 4) 10 | mode(str): iou (intersection over union) or iof (intersection 11 | over foreground) 12 | 13 | Returns: 14 | ious(ndarray): shape (n, k) 15 | """ 16 | 17 | assert mode in ['iou', 'iof'] 18 | 19 | bboxes1 = bboxes1.astype(np.float32) 20 | bboxes2 = bboxes2.astype(np.float32) 21 | rows = bboxes1.shape[0] 22 | cols = bboxes2.shape[0] 23 | ious = np.zeros((rows, cols), dtype=np.float32) 24 | if rows * cols == 0: 25 | return ious 26 | exchange = False 27 | if bboxes1.shape[0] > bboxes2.shape[0]: 28 | bboxes1, bboxes2 = bboxes2, bboxes1 29 | ious = np.zeros((cols, rows), dtype=np.float32) 30 | exchange = True 31 | area1 = (bboxes1[:, 2] - bboxes1[:, 0] + 1) * ( 32 | bboxes1[:, 3] - bboxes1[:, 1] + 1) 33 | area2 = (bboxes2[:, 2] - bboxes2[:, 0] + 1) * ( 34 | bboxes2[:, 3] - bboxes2[:, 1] + 1) 35 | for i in range(bboxes1.shape[0]): 36 | x_start = np.maximum(bboxes1[i, 0], bboxes2[:, 0]) 37 | y_start = np.maximum(bboxes1[i, 1], bboxes2[:, 1]) 38 | x_end = np.minimum(bboxes1[i, 2], bboxes2[:, 2]) 39 | y_end = np.minimum(bboxes1[i, 3], bboxes2[:, 3]) 40 | overlap = np.maximum(x_end - x_start + 1, 0) * np.maximum( 41 | y_end - y_start + 1, 0) 42 | if mode == 'iou': 43 | union = area1[i] + area2 - overlap 44 | else: 45 | union = area1[i] if not exchange else area2 46 | ious[i, :] = overlap / union 47 | if exchange: 48 | ious = ious.T 49 | return ious 50 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/fp16/__init__.py: -------------------------------------------------------------------------------- 1 | from .decorators import auto_fp16, force_fp32 2 | from .hooks import Fp16OptimizerHook, wrap_fp16_model 3 | 4 | __all__ = ['auto_fp16', 'force_fp32', 'Fp16OptimizerHook', 'wrap_fp16_model'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/fp16/utils.py: -------------------------------------------------------------------------------- 1 | from collections import abc 2 | 3 | import numpy as np 4 | import torch 5 | 6 | 7 | def cast_tensor_type(inputs, src_type, dst_type): 8 | if isinstance(inputs, torch.Tensor): 9 | return inputs.to(dst_type) 10 | elif isinstance(inputs, str): 11 | return inputs 12 | elif isinstance(inputs, np.ndarray): 13 | return inputs 14 | elif isinstance(inputs, abc.Mapping): 15 | return type(inputs)({ 16 | k: cast_tensor_type(v, src_type, dst_type) 17 | for k, v in inputs.items() 18 | }) 19 | elif isinstance(inputs, abc.Iterable): 20 | return type(inputs)( 21 | cast_tensor_type(item, src_type, dst_type) for item in inputs) 22 | else: 23 | return inputs 24 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/mask/__init__.py: -------------------------------------------------------------------------------- 1 | from .utils import split_combined_polys 2 | from .mask_target import mask_target 3 | 4 | __all__ = ['split_combined_polys', 'mask_target'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/mask/mask_target.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import mmcv 4 | 5 | 6 | def mask_target(pos_proposals_list, pos_assigned_gt_inds_list, gt_masks_list, 7 | cfg): 8 | cfg_list = [cfg for _ in range(len(pos_proposals_list))] 9 | mask_targets = map(mask_target_single, pos_proposals_list, 10 | pos_assigned_gt_inds_list, gt_masks_list, cfg_list) 11 | mask_targets = torch.cat(list(mask_targets)) 12 | return mask_targets 13 | 14 | 15 | def mask_target_single(pos_proposals, pos_assigned_gt_inds, gt_masks, cfg): 16 | mask_size = cfg.mask_size 17 | num_pos = pos_proposals.size(0) 18 | mask_targets = [] 19 | if num_pos > 0: 20 | proposals_np = pos_proposals.cpu().numpy() 21 | pos_assigned_gt_inds = pos_assigned_gt_inds.cpu().numpy() 22 | for i in range(num_pos): 23 | gt_mask = gt_masks[pos_assigned_gt_inds[i]] 24 | bbox = proposals_np[i, :].astype(np.int32) 25 | x1, y1, x2, y2 = bbox 26 | w = np.maximum(x2 - x1 + 1, 1) 27 | h = np.maximum(y2 - y1 + 1, 1) 28 | # mask is uint8 both before and after resizing 29 | target = mmcv.imresize(gt_mask[y1:y1 + h, x1:x1 + w], 30 | (mask_size, mask_size)) 31 | mask_targets.append(target) 32 | mask_targets = torch.from_numpy(np.stack(mask_targets)).float().to( 33 | pos_proposals.device) 34 | else: 35 | mask_targets = pos_proposals.new_zeros((0, mask_size, mask_size)) 36 | return mask_targets 37 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/mask/utils.py: -------------------------------------------------------------------------------- 1 | import mmcv 2 | 3 | 4 | def split_combined_polys(polys, poly_lens, polys_per_mask): 5 | """Split the combined 1-D polys into masks. 6 | 7 | A mask is represented as a list of polys, and a poly is represented as 8 | a 1-D array. In dataset, all masks are concatenated into a single 1-D 9 | tensor. Here we need to split the tensor into original representations. 10 | 11 | Args: 12 | polys (list): a list (length = image num) of 1-D tensors 13 | poly_lens (list): a list (length = image num) of poly length 14 | polys_per_mask (list): a list (length = image num) of poly number 15 | of each mask 16 | 17 | Returns: 18 | list: a list (length = image num) of list (length = mask num) of 19 | list (length = poly num) of numpy array 20 | """ 21 | mask_polys_list = [] 22 | for img_id in range(len(polys)): 23 | polys_single = polys[img_id] 24 | polys_lens_single = poly_lens[img_id].tolist() 25 | polys_per_mask_single = polys_per_mask[img_id].tolist() 26 | 27 | split_polys = mmcv.slice_list(polys_single, polys_lens_single) 28 | mask_polys = mmcv.slice_list(split_polys, polys_per_mask_single) 29 | mask_polys_list.append(mask_polys) 30 | return mask_polys_list 31 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/post_processing/__init__.py: -------------------------------------------------------------------------------- 1 | from .bbox_nms import multiclass_nms 2 | from .merge_augs import (merge_aug_proposals, merge_aug_bboxes, 3 | merge_aug_scores, merge_aug_masks) 4 | 5 | __all__ = [ 6 | 'multiclass_nms', 'merge_aug_proposals', 'merge_aug_bboxes', 7 | 'merge_aug_scores', 'merge_aug_masks' 8 | ] 9 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .dist_utils import allreduce_grads, DistOptimizerHook 2 | from .misc import tensor2imgs, unmap, multi_apply 3 | from .avg_meter import AverageMeter 4 | 5 | __all__ = [ 6 | 'allreduce_grads', 'DistOptimizerHook', 'tensor2imgs', 'unmap', 7 | 'multi_apply', 'AverageMeter' 8 | ] 9 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/adv_checkpoint.py: -------------------------------------------------------------------------------- 1 | from mmcv.runner.hooks.checkpoint import CheckpointHook 2 | from mmcv.runner.utils import master_only 3 | 4 | 5 | class AdvCheckpointHook(CheckpointHook): 6 | def __int__(self, **kwargs): 7 | super(AdvCheckpointHook, self).__init__(**kwargs) 8 | 9 | @master_only 10 | def after_train_epoch(self, runner): 11 | if not self.every_n_epochs(runner, self.interval): 12 | return 13 | 14 | if not self.out_dir: 15 | self.out_dir = runner.work_dir 16 | runner.save_checkpoint( 17 | self.out_dir, save_optimizer=self.save_optimizer, **self.args) 18 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/adv_optimizer.py: -------------------------------------------------------------------------------- 1 | from mmcv.runner.hooks.optimizer import OptimizerHook 2 | 3 | 4 | class AdvOptimizerHook(OptimizerHook): 5 | 6 | def __int__(self, **kwargs): 7 | super(AdvOptimizerHook, self).__init__(**kwargs) 8 | 9 | def after_train_iter(self, runner): 10 | runner.adv_optimizer.zero_grad() 11 | runner.outputs['adv_loss'].backward() 12 | if self.grad_clip is not None: 13 | self.clip_grads(runner.adv_model.parameters()) 14 | runner.adv_optimizer.step() 15 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/avg_meter.py: -------------------------------------------------------------------------------- 1 | class AverageMeter(object): 2 | """Computes and stores the average and current value""" 3 | 4 | def __init__(self, name, fmt=':f'): 5 | self.name = name 6 | self.fmt = fmt 7 | self.reset() 8 | 9 | def reset(self): 10 | self.val = 0 11 | self.avg = 0 12 | self.sum = 0 13 | self.count = 0 14 | 15 | def update(self, val, n=1): 16 | self.val = val 17 | self.sum += val * n 18 | self.count += n 19 | self.avg = self.sum / self.count 20 | 21 | def __str__(self): 22 | fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' 23 | return fmtstr.format(**self.__dict__) 24 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/dist_utils.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | import torch.distributed as dist 4 | from torch._utils import (_flatten_dense_tensors, _unflatten_dense_tensors, 5 | _take_tensors) 6 | from mmcv.runner import OptimizerHook 7 | 8 | 9 | def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): 10 | if bucket_size_mb > 0: 11 | bucket_size_bytes = bucket_size_mb * 1024 * 1024 12 | buckets = _take_tensors(tensors, bucket_size_bytes) 13 | else: 14 | buckets = OrderedDict() 15 | for tensor in tensors: 16 | tp = tensor.type() 17 | if tp not in buckets: 18 | buckets[tp] = [] 19 | buckets[tp].append(tensor) 20 | buckets = buckets.values() 21 | 22 | for bucket in buckets: 23 | flat_tensors = _flatten_dense_tensors(bucket) 24 | dist.all_reduce(flat_tensors) 25 | flat_tensors.div_(world_size) 26 | for tensor, synced in zip( 27 | bucket, _unflatten_dense_tensors(flat_tensors, bucket)): 28 | tensor.copy_(synced) 29 | 30 | 31 | def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): 32 | grads = [ 33 | param.grad.data for param in params 34 | if param.requires_grad and param.grad is not None 35 | ] 36 | world_size = dist.get_world_size() 37 | if coalesce: 38 | _allreduce_coalesced(grads, world_size, bucket_size_mb) 39 | else: 40 | for tensor in grads: 41 | dist.all_reduce(tensor.div_(world_size)) 42 | 43 | 44 | class DistOptimizerHook(OptimizerHook): 45 | 46 | def __init__(self, grad_clip=None, coalesce=True, bucket_size_mb=-1): 47 | self.grad_clip = grad_clip 48 | self.coalesce = coalesce 49 | self.bucket_size_mb = bucket_size_mb 50 | 51 | def after_train_iter(self, runner): 52 | runner.optimizer.zero_grad() 53 | runner.outputs['loss'].backward() 54 | allreduce_grads(runner.model.parameters(), self.coalesce, 55 | self.bucket_size_mb) 56 | if self.grad_clip is not None: 57 | self.clip_grads(runner.model.parameters()) 58 | runner.optimizer.step() 59 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/lr_hooks.py: -------------------------------------------------------------------------------- 1 | from mmcv.runner.hooks.lr_updater import LrUpdaterHook 2 | 3 | 4 | class PowerLrUpdaterHook(LrUpdaterHook): 5 | 6 | def __init__(self, step, gamma=1., **kwargs): 7 | assert isinstance(step, int) and step > 0 8 | self.step = step 9 | self.gamma = gamma 10 | super(PowerLrUpdaterHook, self).__init__(**kwargs) 11 | 12 | def get_lr(self, runner, base_lr): 13 | progress = runner.epoch if self.by_epoch else runner.iter 14 | 15 | return base_lr if progress == 0 or progress % self.step != 0 else base_lr * self.gamma 16 | 17 | 18 | class SequenceLrUpdaterHook(LrUpdaterHook): 19 | 20 | def __init__(self, seq, **kwargs): 21 | assert isinstance(seq, list) and len(seq) > 0 22 | self.seq = seq 23 | super(SequenceLrUpdaterHook, self).__init__(**kwargs) 24 | 25 | def get_lr(self, runner, base_lr): 26 | progress = runner.epoch if self.by_epoch else runner.iter 27 | 28 | return self.seq[progress] if progress < len(self.seq) else self.seq[-1] 29 | -------------------------------------------------------------------------------- /mmdetection/mmdet/core/utils/misc.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | import mmcv 4 | import numpy as np 5 | from six.moves import map, zip 6 | 7 | 8 | def tensor2imgs(tensor, mean=(0, 0, 0), std=(1, 1, 1), to_rgb=True): 9 | num_imgs = tensor.size(0) 10 | mean = np.array(mean, dtype=np.float32) 11 | std = np.array(std, dtype=np.float32) 12 | imgs = [] 13 | for img_id in range(num_imgs): 14 | img = tensor[img_id, ...].cpu().numpy().transpose(1, 2, 0) 15 | img = mmcv.imdenormalize( 16 | img, mean, std, to_bgr=to_rgb).astype(np.uint8) 17 | imgs.append(np.ascontiguousarray(img)) 18 | return imgs 19 | 20 | 21 | def multi_apply(func, *args, **kwargs): 22 | pfunc = partial(func, **kwargs) if kwargs else func 23 | map_results = map(pfunc, *args) 24 | return tuple(map(list, zip(*map_results))) 25 | 26 | 27 | def unmap(data, count, inds, fill=0): 28 | """ Unmap a subset of item (data) back to the original set of items (of 29 | size count) """ 30 | if data.dim() == 1: 31 | ret = data.new_full((count, ), fill) 32 | ret[inds] = data 33 | else: 34 | new_size = (count, ) + data.size()[1:] 35 | ret = data.new_full(new_size, fill) 36 | ret[inds, :] = data 37 | return ret 38 | -------------------------------------------------------------------------------- /mmdetection/mmdet/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | from .custom import CustomDataset 2 | from .xml_style import XMLDataset 3 | from .coco import CocoDataset 4 | from .voc import VOCDataset 5 | from .wider_face import WIDERFaceDataset 6 | from .loader import GroupSampler, DistributedGroupSampler, build_dataloader, build_dataloader_fuse 7 | from .utils import to_tensor, random_scale, show_ann, get_dataset 8 | from .concat_dataset import ConcatDataset 9 | from .repeat_dataset import RepeatDataset 10 | from .extra_aug import ExtraAugmentation 11 | from .h36m import H36MDataset 12 | from .coco_kpts import COCOKeypoints 13 | from .common import CommonDataset 14 | 15 | __all__ = [ 16 | 'CustomDataset', 'XMLDataset', 'CocoDataset', 'VOCDataset', 'GroupSampler', 17 | 'DistributedGroupSampler', 'build_dataloader', 'to_tensor', 'random_scale', 18 | 'show_ann', 'get_dataset', 'ConcatDataset', 'RepeatDataset', 19 | 'ExtraAugmentation', 'WIDERFaceDataset', 'H36MDataset', 'COCOKeypoints', 'build_dataloader_fuse', 'CommonDataset', 20 | ] 21 | -------------------------------------------------------------------------------- /mmdetection/mmdet/datasets/concat_dataset.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from torch.utils.data.dataset import ConcatDataset as _ConcatDataset 3 | 4 | 5 | class ConcatDataset(_ConcatDataset): 6 | """A wrapper of concatenated dataset. 7 | 8 | Same as :obj:`torch.utils.data.dataset.ConcatDataset`, but 9 | concat the group flag for image aspect ratio. 10 | 11 | Args: 12 | datasets (list[:obj:`Dataset`]): A list of datasets. 13 | """ 14 | 15 | def __init__(self, datasets): 16 | super(ConcatDataset, self).__init__(datasets) 17 | self.CLASSES = datasets[0].CLASSES 18 | if hasattr(datasets[0], 'flag'): 19 | flags = [] 20 | for i in range(0, len(datasets)): 21 | flags.append(datasets[i].flag) 22 | self.flag = np.concatenate(flags) 23 | 24 | if hasattr(datasets[0], 'density'): 25 | density = [] 26 | for i in range(0, len(datasets)): 27 | density.append(datasets[i].density) 28 | self.density = np.concatenate(density) 29 | -------------------------------------------------------------------------------- /mmdetection/mmdet/datasets/loader/__init__.py: -------------------------------------------------------------------------------- 1 | from .build_loader import build_dataloader, build_dataloader_fuse 2 | from .sampler import GroupSampler, DistributedGroupSampler 3 | 4 | __all__ = ['GroupSampler', 'DistributedGroupSampler', 'build_dataloader', 'build_dataloader_fuse'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/datasets/repeat_dataset.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class RepeatDataset(object): 5 | 6 | def __init__(self, dataset, times): 7 | self.dataset = dataset 8 | self.times = times 9 | self.CLASSES = dataset.CLASSES 10 | if hasattr(self.dataset, 'flag'): 11 | self.flag = np.tile(self.dataset.flag, times) 12 | 13 | self._ori_len = len(self.dataset) 14 | 15 | def __getitem__(self, idx): 16 | return self.dataset[idx % self._ori_len] 17 | 18 | def __len__(self): 19 | return self.times * self._ori_len 20 | -------------------------------------------------------------------------------- /mmdetection/mmdet/datasets/voc.py: -------------------------------------------------------------------------------- 1 | from .xml_style import XMLDataset 2 | 3 | 4 | class VOCDataset(XMLDataset): 5 | 6 | CLASSES = ('aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 7 | 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 8 | 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 9 | 'tvmonitor') 10 | 11 | def __init__(self, **kwargs): 12 | super(VOCDataset, self).__init__(**kwargs) 13 | if 'VOC2007' in self.img_prefix: 14 | self.year = 2007 15 | elif 'VOC2012' in self.img_prefix: 16 | self.year = 2012 17 | else: 18 | raise ValueError('Cannot infer dataset year from img_prefix') 19 | -------------------------------------------------------------------------------- /mmdetection/mmdet/datasets/wider_face.py: -------------------------------------------------------------------------------- 1 | import os.path as osp 2 | import xml.etree.ElementTree as ET 3 | 4 | import mmcv 5 | 6 | from .xml_style import XMLDataset 7 | 8 | 9 | class WIDERFaceDataset(XMLDataset): 10 | """ 11 | Reader for the WIDER Face dataset in PASCAL VOC format. 12 | Conversion scripts can be found in 13 | https://github.com/sovrasov/wider-face-pascal-voc-annotations 14 | """ 15 | CLASSES = ('face',) 16 | 17 | def __init__(self, **kwargs): 18 | super(WIDERFaceDataset, self).__init__(**kwargs) 19 | 20 | def load_annotations(self, ann_file): 21 | img_infos = [] 22 | img_ids = mmcv.list_from_file(ann_file) 23 | for img_id in img_ids: 24 | filename = '{}.jpg'.format(img_id) 25 | xml_path = osp.join(self.img_prefix, 'Annotations', 26 | '{}.xml'.format(img_id)) 27 | tree = ET.parse(xml_path) 28 | root = tree.getroot() 29 | size = root.find('size') 30 | width = int(size.find('width').text) 31 | height = int(size.find('height').text) 32 | folder = root.find('folder').text 33 | img_infos.append( 34 | dict(id=img_id, filename=osp.join(folder, filename), 35 | width=width, height=height)) 36 | 37 | return img_infos 38 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .backbones import * # noqa: F401,F403 2 | from .necks import * # noqa: F401,F403 3 | from .roi_extractors import * # noqa: F401,F403 4 | from .anchor_heads import * # noqa: F401,F403 5 | from .shared_heads import * # noqa: F401,F403 6 | from .bbox_heads import * # noqa: F401,F403 7 | from .mask_heads import * # noqa: F401,F403 8 | from .losses import * # noqa: F401,F403 9 | from .detectors import * # noqa: F401,F403 10 | from .smpl_heads import * 11 | from .registry import (BACKBONES, NECKS, ROI_EXTRACTORS, SHARED_HEADS, HEADS, 12 | LOSSES, DETECTORS) 13 | from .builder import (build_backbone, build_neck, build_roi_extractor, 14 | build_shared_head, build_head, build_loss, 15 | build_detector) 16 | 17 | __all__ = [ 18 | 'BACKBONES', 'NECKS', 'ROI_EXTRACTORS', 'SHARED_HEADS', 'HEADS', 'LOSSES', 19 | 'DETECTORS', 'build_backbone', 'build_neck', 'build_roi_extractor', 20 | 'build_shared_head', 'build_head', 'build_loss', 'build_detector' 21 | ] 22 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/anchor_heads/__init__.py: -------------------------------------------------------------------------------- 1 | from .anchor_head import AnchorHead 2 | from .guided_anchor_head import GuidedAnchorHead, FeatureAdaption 3 | from .fcos_head import FCOSHead 4 | from .rpn_head import RPNHead 5 | from .ga_rpn_head import GARPNHead 6 | from .retina_head import RetinaHead 7 | from .ga_retina_head import GARetinaHead 8 | from .ssd_head import SSDHead 9 | 10 | __all__ = [ 11 | 'AnchorHead', 'GuidedAnchorHead', 'FeatureAdaption', 'RPNHead', 12 | 'GARPNHead', 'RetinaHead', 'GARetinaHead', 'SSDHead', 'FCOSHead' 13 | ] 14 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/backbones/__init__.py: -------------------------------------------------------------------------------- 1 | from .resnet import ResNet, make_res_layer 2 | from .resnext import ResNeXt 3 | from .ssd_vgg import SSDVGG 4 | from .hrnet import HRNet 5 | 6 | __all__ = ['ResNet', 'make_res_layer', 'ResNeXt', 'SSDVGG', 'HRNet'] 7 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/bbox_heads/__init__.py: -------------------------------------------------------------------------------- 1 | from .bbox_head import BBoxHead 2 | from .convfc_bbox_head import ConvFCBBoxHead, SharedFCBBoxHead 3 | 4 | __all__ = ['BBoxHead', 'ConvFCBBoxHead', 'SharedFCBBoxHead'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/builder.py: -------------------------------------------------------------------------------- 1 | import mmcv 2 | from torch import nn 3 | 4 | from .registry import (BACKBONES, NECKS, ROI_EXTRACTORS, SHARED_HEADS, HEADS, 5 | LOSSES, DETECTORS) 6 | 7 | 8 | def _build_module(cfg, registry, default_args): 9 | assert isinstance(cfg, dict) and 'type' in cfg 10 | assert isinstance(default_args, dict) or default_args is None 11 | args = cfg.copy() 12 | obj_type = args.pop('type') 13 | if mmcv.is_str(obj_type): 14 | if obj_type not in registry.module_dict: 15 | raise KeyError('{} is not in the {} registry'.format( 16 | obj_type, registry.name)) 17 | obj_type = registry.module_dict[obj_type] 18 | elif not isinstance(obj_type, type): 19 | raise TypeError('type must be a str or valid type, but got {}'.format( 20 | type(obj_type))) 21 | if default_args is not None: 22 | for name, value in default_args.items(): 23 | args.setdefault(name, value) 24 | return obj_type(**args) 25 | 26 | 27 | def build(cfg, registry, default_args=None): 28 | if isinstance(cfg, list): 29 | modules = [_build_module(cfg_, registry, default_args) for cfg_ in cfg] 30 | return nn.Sequential(*modules) 31 | else: 32 | return _build_module(cfg, registry, default_args) 33 | 34 | 35 | def build_backbone(cfg): 36 | return build(cfg, BACKBONES) 37 | 38 | 39 | def build_neck(cfg): 40 | return build(cfg, NECKS) 41 | 42 | 43 | def build_roi_extractor(cfg): 44 | return build(cfg, ROI_EXTRACTORS) 45 | 46 | 47 | def build_shared_head(cfg): 48 | return build(cfg, SHARED_HEADS) 49 | 50 | 51 | def build_head(cfg): 52 | return build(cfg, HEADS) 53 | 54 | 55 | def build_loss(cfg): 56 | return build(cfg, LOSSES) 57 | 58 | 59 | def build_detector(cfg, train_cfg=None, test_cfg=None): 60 | return build(cfg, DETECTORS, dict(train_cfg=train_cfg, test_cfg=test_cfg)) 61 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/detectors/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import BaseDetector 2 | from .single_stage import SingleStageDetector 3 | from .two_stage import TwoStageDetector 4 | from .rpn import RPN 5 | from .fast_rcnn import FastRCNN 6 | from .faster_rcnn import FasterRCNN 7 | from .mask_rcnn import MaskRCNN 8 | from .cascade_rcnn import CascadeRCNN 9 | from .htc import HybridTaskCascade 10 | from .retinanet import RetinaNet 11 | from .fcos import FCOS 12 | from .grid_rcnn import GridRCNN 13 | from .mask_scoring_rcnn import MaskScoringRCNN 14 | from .smpl_rcnn import SMPLRCNN 15 | from .bmp import BMP 16 | 17 | __all__ = [ 18 | 'BaseDetector', 'SingleStageDetector', 'TwoStageDetector', 'RPN', 19 | 'FastRCNN', 'FasterRCNN', 'MaskRCNN', 'CascadeRCNN', 'HybridTaskCascade', 20 | 'RetinaNet', 'FCOS', 'GridRCNN', 'MaskScoringRCNN', 'SMPLRCNN', 'BMP' 21 | ] 22 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/detectors/fast_rcnn.py: -------------------------------------------------------------------------------- 1 | from .two_stage import TwoStageDetector 2 | from ..registry import DETECTORS 3 | 4 | 5 | @DETECTORS.register_module 6 | class FastRCNN(TwoStageDetector): 7 | 8 | def __init__(self, 9 | backbone, 10 | bbox_roi_extractor, 11 | bbox_head, 12 | train_cfg, 13 | test_cfg, 14 | neck=None, 15 | shared_head=None, 16 | mask_roi_extractor=None, 17 | mask_head=None, 18 | pretrained=None): 19 | super(FastRCNN, self).__init__( 20 | backbone=backbone, 21 | neck=neck, 22 | shared_head=shared_head, 23 | bbox_roi_extractor=bbox_roi_extractor, 24 | bbox_head=bbox_head, 25 | train_cfg=train_cfg, 26 | test_cfg=test_cfg, 27 | mask_roi_extractor=mask_roi_extractor, 28 | mask_head=mask_head, 29 | pretrained=pretrained) 30 | 31 | def forward_test(self, imgs, img_metas, proposals, **kwargs): 32 | for var, name in [(imgs, 'imgs'), (img_metas, 'img_metas')]: 33 | if not isinstance(var, list): 34 | raise TypeError('{} must be a list, but got {}'.format( 35 | name, type(var))) 36 | 37 | num_augs = len(imgs) 38 | if num_augs != len(img_metas): 39 | raise ValueError( 40 | 'num of augmentations ({}) != num of image meta ({})'.format( 41 | len(imgs), len(img_metas))) 42 | # TODO: remove the restriction of imgs_per_gpu == 1 when prepared 43 | imgs_per_gpu = imgs[0].size(0) 44 | assert imgs_per_gpu == 1 45 | 46 | if num_augs == 1: 47 | return self.simple_test(imgs[0], img_metas[0], proposals[0], 48 | **kwargs) 49 | else: 50 | return self.aug_test(imgs, img_metas, proposals, **kwargs) 51 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/detectors/faster_rcnn.py: -------------------------------------------------------------------------------- 1 | from .two_stage import TwoStageDetector 2 | from ..registry import DETECTORS 3 | 4 | 5 | @DETECTORS.register_module 6 | class FasterRCNN(TwoStageDetector): 7 | 8 | def __init__(self, 9 | backbone, 10 | rpn_head, 11 | bbox_roi_extractor, 12 | bbox_head, 13 | train_cfg, 14 | test_cfg, 15 | neck=None, 16 | shared_head=None, 17 | pretrained=None): 18 | super(FasterRCNN, self).__init__( 19 | backbone=backbone, 20 | neck=neck, 21 | shared_head=shared_head, 22 | rpn_head=rpn_head, 23 | bbox_roi_extractor=bbox_roi_extractor, 24 | bbox_head=bbox_head, 25 | train_cfg=train_cfg, 26 | test_cfg=test_cfg, 27 | pretrained=pretrained) 28 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/detectors/fcos.py: -------------------------------------------------------------------------------- 1 | from .single_stage import SingleStageDetector 2 | from ..registry import DETECTORS 3 | 4 | 5 | @DETECTORS.register_module 6 | class FCOS(SingleStageDetector): 7 | 8 | def __init__(self, 9 | backbone, 10 | neck, 11 | bbox_head, 12 | train_cfg=None, 13 | test_cfg=None, 14 | pretrained=None): 15 | super(FCOS, self).__init__(backbone, neck, bbox_head, train_cfg, 16 | test_cfg, pretrained) 17 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/detectors/mask_rcnn.py: -------------------------------------------------------------------------------- 1 | from .two_stage import TwoStageDetector 2 | from ..registry import DETECTORS 3 | 4 | 5 | @DETECTORS.register_module 6 | class MaskRCNN(TwoStageDetector): 7 | 8 | def __init__(self, 9 | backbone, 10 | rpn_head, 11 | bbox_roi_extractor, 12 | bbox_head, 13 | mask_roi_extractor, 14 | mask_head, 15 | train_cfg, 16 | test_cfg, 17 | neck=None, 18 | shared_head=None, 19 | pretrained=None): 20 | super(MaskRCNN, self).__init__( 21 | backbone=backbone, 22 | neck=neck, 23 | shared_head=shared_head, 24 | rpn_head=rpn_head, 25 | bbox_roi_extractor=bbox_roi_extractor, 26 | bbox_head=bbox_head, 27 | mask_roi_extractor=mask_roi_extractor, 28 | mask_head=mask_head, 29 | train_cfg=train_cfg, 30 | test_cfg=test_cfg, 31 | pretrained=pretrained) 32 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/detectors/retinanet.py: -------------------------------------------------------------------------------- 1 | from .single_stage import SingleStageDetector 2 | from ..registry import DETECTORS 3 | 4 | 5 | @DETECTORS.register_module 6 | class RetinaNet(SingleStageDetector): 7 | 8 | def __init__(self, 9 | backbone, 10 | neck, 11 | bbox_head, 12 | train_cfg=None, 13 | test_cfg=None, 14 | pretrained=None): 15 | super(RetinaNet, self).__init__(backbone, neck, bbox_head, train_cfg, 16 | test_cfg, pretrained) 17 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/losses/__init__.py: -------------------------------------------------------------------------------- 1 | from .accuracy import accuracy, Accuracy 2 | from .cross_entropy_loss import (cross_entropy, binary_cross_entropy, 3 | mask_cross_entropy, CrossEntropyLoss) 4 | from .focal_loss import sigmoid_focal_loss, FocalLoss 5 | from .smooth_l1_loss import smooth_l1_loss, SmoothL1Loss 6 | from .ghm_loss import GHMC, GHMR 7 | from .balanced_l1_loss import balanced_l1_loss, BalancedL1Loss 8 | from .mse_loss import mse_loss, MSELoss 9 | from .iou_loss import iou_loss, bounded_iou_loss, IoULoss, BoundedIoULoss 10 | from .utils import reduce_loss, weight_reduce_loss, weighted_loss 11 | from .bmp_loss import BMPLoss 12 | 13 | __all__ = [ 14 | 'accuracy', 'Accuracy', 'cross_entropy', 'binary_cross_entropy', 15 | 'mask_cross_entropy', 'CrossEntropyLoss', 'sigmoid_focal_loss', 16 | 'FocalLoss', 'smooth_l1_loss', 'SmoothL1Loss', 'balanced_l1_loss', 17 | 'BalancedL1Loss', 'mse_loss', 'MSELoss', 'iou_loss', 'bounded_iou_loss', 18 | 'IoULoss', 'BoundedIoULoss', 'GHMC', 'GHMR', 'reduce_loss', 19 | 'weight_reduce_loss', 'weighted_loss', 'BMPLoss' 20 | ] 21 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/losses/accuracy.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | def accuracy(pred, target, topk=1): 5 | assert isinstance(topk, (int, tuple)) 6 | if isinstance(topk, int): 7 | topk = (topk, ) 8 | return_single = True 9 | else: 10 | return_single = False 11 | 12 | maxk = max(topk) 13 | _, pred_label = pred.topk(maxk, dim=1) 14 | pred_label = pred_label.t() 15 | correct = pred_label.eq(target.view(1, -1).expand_as(pred_label)) 16 | 17 | res = [] 18 | for k in topk: 19 | correct_k = correct[:k].view(-1).float().sum(0, keepdim=True) 20 | res.append(correct_k.mul_(100.0 / pred.size(0))) 21 | return res[0] if return_single else res 22 | 23 | 24 | class Accuracy(nn.Module): 25 | 26 | def __init__(self, topk=(1, )): 27 | super().__init__() 28 | self.topk = topk 29 | 30 | def forward(self, pred, target): 31 | return accuracy(pred, target, self.topk) 32 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/losses/balanced_l1_loss.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | 5 | from .utils import weighted_loss 6 | from ..registry import LOSSES 7 | 8 | 9 | @weighted_loss 10 | def balanced_l1_loss(pred, 11 | target, 12 | beta=1.0, 13 | alpha=0.5, 14 | gamma=1.5, 15 | reduction='mean'): 16 | assert beta > 0 17 | assert pred.size() == target.size() and target.numel() > 0 18 | 19 | diff = torch.abs(pred - target) 20 | b = np.e**(gamma / alpha) - 1 21 | loss = torch.where( 22 | diff < beta, alpha / b * 23 | (b * diff + 1) * torch.log(b * diff / beta + 1) - alpha * diff, 24 | gamma * diff + gamma / b - alpha * beta) 25 | 26 | return loss 27 | 28 | 29 | @LOSSES.register_module 30 | class BalancedL1Loss(nn.Module): 31 | """Balanced L1 Loss 32 | 33 | arXiv: https://arxiv.org/pdf/1904.02701.pdf (CVPR 2019) 34 | """ 35 | 36 | def __init__(self, 37 | alpha=0.5, 38 | gamma=1.5, 39 | beta=1.0, 40 | reduction='mean', 41 | loss_weight=1.0): 42 | super(BalancedL1Loss, self).__init__() 43 | self.alpha = alpha 44 | self.gamma = gamma 45 | self.beta = beta 46 | self.reduction = reduction 47 | self.loss_weight = loss_weight 48 | 49 | def forward(self, 50 | pred, 51 | target, 52 | weight=None, 53 | avg_factor=None, 54 | reduction_override=None, 55 | **kwargs): 56 | assert reduction_override in (None, 'none', 'mean', 'sum') 57 | reduction = ( 58 | reduction_override if reduction_override else self.reduction) 59 | loss_bbox = self.loss_weight * balanced_l1_loss( 60 | pred, 61 | target, 62 | weight, 63 | alpha=self.alpha, 64 | gamma=self.gamma, 65 | beta=self.beta, 66 | reduction=reduction, 67 | avg_factor=avg_factor, 68 | **kwargs) 69 | return loss_bbox 70 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/losses/mse_loss.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch.nn.functional as F 3 | 4 | from .utils import weighted_loss 5 | from ..registry import LOSSES 6 | 7 | mse_loss = weighted_loss(F.mse_loss) 8 | 9 | 10 | @LOSSES.register_module 11 | class MSELoss(nn.Module): 12 | 13 | def __init__(self, reduction='mean', loss_weight=1.0): 14 | super().__init__() 15 | self.reduction = reduction 16 | self.loss_weight = loss_weight 17 | 18 | def forward(self, pred, target, weight=None, avg_factor=None): 19 | loss = self.loss_weight * mse_loss( 20 | pred, 21 | target, 22 | weight, 23 | reduction=self.reduction, 24 | avg_factor=avg_factor) 25 | return loss 26 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/losses/smooth_l1_loss.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | from .utils import weighted_loss 5 | from ..registry import LOSSES 6 | 7 | 8 | @weighted_loss 9 | def smooth_l1_loss(pred, target, beta=1.0): 10 | assert beta > 0 11 | assert pred.size() == target.size() and target.numel() > 0 12 | diff = torch.abs(pred - target) 13 | loss = torch.where(diff < beta, 0.5 * diff * diff / beta, 14 | diff - 0.5 * beta) 15 | return loss 16 | 17 | 18 | @LOSSES.register_module 19 | class SmoothL1Loss(nn.Module): 20 | 21 | def __init__(self, beta=1.0, reduction='mean', loss_weight=1.0): 22 | super(SmoothL1Loss, self).__init__() 23 | self.beta = beta 24 | self.reduction = reduction 25 | self.loss_weight = loss_weight 26 | 27 | def forward(self, 28 | pred, 29 | target, 30 | weight=None, 31 | avg_factor=None, 32 | reduction_override=None, 33 | **kwargs): 34 | assert reduction_override in (None, 'none', 'mean', 'sum') 35 | reduction = ( 36 | reduction_override if reduction_override else self.reduction) 37 | loss_bbox = self.loss_weight * smooth_l1_loss( 38 | pred, 39 | target, 40 | weight, 41 | beta=self.beta, 42 | reduction=reduction, 43 | avg_factor=avg_factor, 44 | **kwargs) 45 | return loss_bbox 46 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/mask_heads/__init__.py: -------------------------------------------------------------------------------- 1 | from .fcn_mask_head import FCNMaskHead 2 | from .fused_semantic_head import FusedSemanticHead 3 | from .grid_head import GridHead 4 | from .htc_mask_head import HTCMaskHead 5 | from .maskiou_head import MaskIoUHead 6 | 7 | from .fcn_kpts_head import FCNKptsHead 8 | 9 | __all__ = [ 10 | 'FCNMaskHead', 'HTCMaskHead', 'FusedSemanticHead', 'GridHead', 11 | 'MaskIoUHead', 'FCNKptsHead', 12 | ] 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/mask_heads/htc_mask_head.py: -------------------------------------------------------------------------------- 1 | from .fcn_mask_head import FCNMaskHead 2 | from ..registry import HEADS 3 | from ..utils import ConvModule 4 | 5 | 6 | @HEADS.register_module 7 | class HTCMaskHead(FCNMaskHead): 8 | 9 | def __init__(self, *args, **kwargs): 10 | super(HTCMaskHead, self).__init__(*args, **kwargs) 11 | self.conv_res = ConvModule( 12 | self.conv_out_channels, 13 | self.conv_out_channels, 14 | 1, 15 | conv_cfg=self.conv_cfg, 16 | norm_cfg=self.norm_cfg) 17 | 18 | def init_weights(self): 19 | super(HTCMaskHead, self).init_weights() 20 | self.conv_res.init_weights() 21 | 22 | def forward(self, x, res_feat=None, return_logits=True, return_feat=True): 23 | if res_feat is not None: 24 | res_feat = self.conv_res(res_feat) 25 | x = x + res_feat 26 | for conv in self.convs: 27 | x = conv(x) 28 | res_feat = x 29 | outs = [] 30 | if return_logits: 31 | x = self.upsample(x) 32 | if self.upsample_method == 'deconv': 33 | x = self.relu(x) 34 | mask_pred = self.conv_logits(x) 35 | outs.append(mask_pred) 36 | if return_feat: 37 | outs.append(res_feat) 38 | return outs if len(outs) > 1 else outs[0] 39 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/necks/__init__.py: -------------------------------------------------------------------------------- 1 | from .fpn import FPN 2 | from .bfp import BFP 3 | from .hrfpn import HRFPN 4 | 5 | __all__ = ['FPN', 'BFP', 'HRFPN'] 6 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | from .non_local import NonLocal2D 2 | from .generalized_attention import GeneralizedAttention 3 | 4 | __all__ = ['NonLocal2D', 'GeneralizedAttention'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/registry.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | class Registry(object): 5 | 6 | def __init__(self, name): 7 | self._name = name 8 | self._module_dict = dict() 9 | 10 | @property 11 | def name(self): 12 | return self._name 13 | 14 | @property 15 | def module_dict(self): 16 | return self._module_dict 17 | 18 | def _register_module(self, module_class): 19 | """Register a module. 20 | 21 | Args: 22 | module (:obj:`nn.Module`): Module to be registered. 23 | """ 24 | if not issubclass(module_class, nn.Module): 25 | raise TypeError( 26 | 'module must be a child of nn.Module, but got {}'.format( 27 | module_class)) 28 | module_name = module_class.__name__ 29 | if module_name in self._module_dict: 30 | raise KeyError('{} is already registered in {}'.format( 31 | module_name, self.name)) 32 | self._module_dict[module_name] = module_class 33 | 34 | def register_module(self, cls): 35 | self._register_module(cls) 36 | return cls 37 | 38 | 39 | BACKBONES = Registry('backbone') 40 | NECKS = Registry('neck') 41 | ROI_EXTRACTORS = Registry('roi_extractor') 42 | SHARED_HEADS = Registry('shared_head') 43 | HEADS = Registry('head') 44 | LOSSES = Registry('loss') 45 | DETECTORS = Registry('detector') 46 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/roi_extractors/__init__.py: -------------------------------------------------------------------------------- 1 | from .single_level import SingleRoIExtractor 2 | 3 | __all__ = ['SingleRoIExtractor'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/shared_heads/__init__.py: -------------------------------------------------------------------------------- 1 | from .res_layer import ResLayer 2 | 3 | __all__ = ['ResLayer'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/smpl_heads/__init__.py: -------------------------------------------------------------------------------- 1 | from .bmp_head import BMPHead 2 | 3 | __all__ = ['BMPHead'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .conv_ws import conv_ws_2d, ConvWS2d 2 | from .conv_module import build_conv_layer, ConvModule 3 | from .norm import build_norm_layer 4 | from .scale import Scale 5 | from .weight_init import (xavier_init, normal_init, uniform_init, kaiming_init, 6 | bias_init_with_prob) 7 | 8 | __all__ = [ 9 | 'conv_ws_2d', 'ConvWS2d', 'build_conv_layer', 'ConvModule', 10 | 'build_norm_layer', 'xavier_init', 'normal_init', 'uniform_init', 11 | 'kaiming_init', 'bias_init_with_prob', 'Scale' 12 | ] 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/camera.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | 4 | 5 | class PerspectiveCamera(object): 6 | def __init__(): 7 | pass 8 | 9 | def __call__(points, batch_size, rotation, 10 | translation, focal_length, camera_center): 11 | """ 12 | This function computes the perspective projection of a set of points. 13 | Input: 14 | points (bs, N, 3): 3D points 15 | rotation (bs, 3, 3): Camera rotation 16 | translation (bs, 3): Camera translation 17 | focal_length (bs,) or scalar: Focal length 18 | camera_center (bs, 2): Camera center 19 | """ 20 | K = torch.zeros([batch_size, 3, 3], device=points.device) 21 | K[:,0,0] = focal_length 22 | K[:,1,1] = focal_length 23 | K[:,2,2] = 1. 24 | K[:,:-1, -1] = camera_center 25 | 26 | # Transform points 27 | points = torch.einsum('bij,bkj->bki', rotation, points) 28 | points = points + translation.unsqueeze(1) 29 | 30 | # Apply perspective distortion 31 | projected_points = points / points[:,:,-1].unsqueeze(-1) 32 | 33 | # Apply camera intrinsics 34 | projected_points = torch.einsum('bij,bkj->bki', K, projected_points) 35 | 36 | return projected_points[:, :, :-1] -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/conv_ws.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch.nn.functional as F 3 | 4 | 5 | def conv_ws_2d(input, 6 | weight, 7 | bias=None, 8 | stride=1, 9 | padding=0, 10 | dilation=1, 11 | groups=1, 12 | eps=1e-5): 13 | c_in = weight.size(0) 14 | weight_flat = weight.view(c_in, -1) 15 | mean = weight_flat.mean(dim=1, keepdim=True).view(c_in, 1, 1, 1) 16 | std = weight_flat.std(dim=1, keepdim=True).view(c_in, 1, 1, 1) 17 | weight = (weight - mean) / (std + eps) 18 | return F.conv2d(input, weight, bias, stride, padding, dilation, groups) 19 | 20 | 21 | class ConvWS2d(nn.Conv2d): 22 | 23 | def __init__(self, 24 | in_channels, 25 | out_channels, 26 | kernel_size, 27 | stride=1, 28 | padding=0, 29 | dilation=1, 30 | groups=1, 31 | bias=True, 32 | eps=1e-5): 33 | super(ConvWS2d, self).__init__( 34 | in_channels, 35 | out_channels, 36 | kernel_size, 37 | stride=stride, 38 | padding=padding, 39 | dilation=dilation, 40 | groups=groups, 41 | bias=bias) 42 | self.eps = eps 43 | 44 | def forward(self, x): 45 | return conv_ws_2d(x, self.weight, self.bias, self.stride, self.padding, 46 | self.dilation, self.groups, self.eps) 47 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/kpts.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | import torch.functional as F 4 | import numpy as np 5 | import mmcv 6 | import cv2 7 | 8 | 9 | def kpts_target(pos_proposals_list, pos_assigned_gt_inds_list, gt_kpts_list, 10 | cfg): 11 | cfg_list = [cfg for _ in range(len(pos_proposals_list))] 12 | mask_targets = map(kpts_target_single, pos_proposals_list, 13 | pos_assigned_gt_inds_list, gt_kpts_list, cfg_list) 14 | mask_targets = torch.cat(list(mask_targets)) 15 | return mask_targets 16 | 17 | 18 | @torch.no_grad() 19 | def kpts_target_single(pos_proposals, pos_assigned_gt_inds, gt_kpts, cfg): 20 | heatmap_size = cfg.heatmap_size 21 | num_pos = pos_proposals.size(0) 22 | mask_targets = [] 23 | if num_pos > 0: 24 | proposals_np = pos_proposals.cpu().numpy() 25 | pos_assigned_gt_inds = pos_assigned_gt_inds.cpu().numpy() 26 | for i in range(num_pos): 27 | cur_gt_kpts = gt_kpts[pos_assigned_gt_inds[i]] 28 | bbox = proposals_np[i, :].astype(np.int32) 29 | x1, y1, x2, y2 = bbox 30 | w = np.maximum(x2 - x1 + 1, 1) 31 | h = np.maximum(y2 - y1 + 1, 1) 32 | target = np.zeros((cur_gt_kpts.shape[0], heatmap_size, heatmap_size)) 33 | for k_id, kp in enumerate(cur_gt_kpts.cpu().numpy()): 34 | y_roi, x_roi = int(np.round(heatmap_size * (kp[1] - y1) / h)), int( 35 | np.round(heatmap_size * (kp[0] - x1) / w)) 36 | if kp[-1] != 0 and y_roi > 0 and x_roi > 0 and y_roi < heatmap_size and x_roi < heatmap_size: 37 | target[k_id, y_roi, x_roi] = 1 38 | target[k_id] = cv2.GaussianBlur(target[k_id], cfg.gamma, 0) 39 | am = np.amax(target[k_id]) 40 | target[k_id] /= am 41 | mask_targets.append(target) 42 | mask_targets = torch.from_numpy(np.stack(mask_targets)).float().to( 43 | pos_proposals.device) 44 | else: 45 | mask_targets = pos_proposals.new_zeros((0, heatmap_size, heatmap_size)) 46 | return mask_targets 47 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/norm.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | norm_cfg = { 4 | # format: layer_type: (abbreviation, module) 5 | 'BN': ('bn', nn.BatchNorm2d), 6 | 'SyncBN': ('bn', nn.SyncBatchNorm), 7 | 'GN': ('gn', nn.GroupNorm), 8 | # and potentially 'SN' 9 | } 10 | 11 | 12 | def build_norm_layer(cfg, num_features, postfix=''): 13 | """ Build normalization layer 14 | 15 | Args: 16 | cfg (dict): cfg should contain: 17 | type (str): identify norm layer type. 18 | layer args: args needed to instantiate a norm layer. 19 | requires_grad (bool): [optional] whether stop gradient updates 20 | num_features (int): number of channels from input. 21 | postfix (int, str): appended into norm abbreviation to 22 | create named layer. 23 | 24 | Returns: 25 | name (str): abbreviation + postfix 26 | layer (nn.Module): created norm layer 27 | """ 28 | assert isinstance(cfg, dict) and 'type' in cfg 29 | cfg_ = cfg.copy() 30 | 31 | layer_type = cfg_.pop('type') 32 | if layer_type not in norm_cfg: 33 | raise KeyError('Unrecognized norm type {}'.format(layer_type)) 34 | else: 35 | abbr, norm_layer = norm_cfg[layer_type] 36 | if norm_layer is None: 37 | raise NotImplementedError 38 | 39 | assert isinstance(postfix, (int, str)) 40 | name = abbr + str(postfix) 41 | 42 | requires_grad = cfg_.pop('requires_grad', True) 43 | cfg_.setdefault('eps', 1e-5) 44 | if layer_type != 'GN': 45 | layer = norm_layer(num_features, **cfg_) 46 | if layer_type == 'SyncBN': 47 | layer._specify_ddp_gpu_num(1) 48 | else: 49 | assert 'num_groups' in cfg_ 50 | layer = norm_layer(num_channels=num_features, **cfg_) 51 | 52 | for param in layer.parameters(): 53 | param.requires_grad = requires_grad 54 | 55 | return name, layer 56 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/scale.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | 5 | class Scale(nn.Module): 6 | 7 | def __init__(self, scale=1.0): 8 | super(Scale, self).__init__() 9 | self.scale = nn.Parameter(torch.tensor(scale, dtype=torch.float)) 10 | 11 | def forward(self, x): 12 | return x * self.scale 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/smpl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/models/utils/smpl/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/models/utils/weight_init.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch.nn as nn 3 | 4 | 5 | def xavier_init(module, gain=1, bias=0, distribution='normal'): 6 | assert distribution in ['uniform', 'normal'] 7 | if distribution == 'uniform': 8 | nn.init.xavier_uniform_(module.weight, gain=gain) 9 | else: 10 | nn.init.xavier_normal_(module.weight, gain=gain) 11 | if hasattr(module, 'bias'): 12 | nn.init.constant_(module.bias, bias) 13 | 14 | 15 | def normal_init(module, mean=0, std=1, bias=0): 16 | nn.init.normal_(module.weight, mean, std) 17 | if hasattr(module, 'bias'): 18 | nn.init.constant_(module.bias, bias) 19 | 20 | 21 | def uniform_init(module, a=0, b=1, bias=0): 22 | nn.init.uniform_(module.weight, a, b) 23 | if hasattr(module, 'bias'): 24 | nn.init.constant_(module.bias, bias) 25 | 26 | 27 | def kaiming_init(module, 28 | mode='fan_out', 29 | nonlinearity='relu', 30 | bias=0, 31 | distribution='normal'): 32 | assert distribution in ['uniform', 'normal'] 33 | if distribution == 'uniform': 34 | nn.init.kaiming_uniform_( 35 | module.weight, mode=mode, nonlinearity=nonlinearity) 36 | else: 37 | nn.init.kaiming_normal_( 38 | module.weight, mode=mode, nonlinearity=nonlinearity) 39 | if hasattr(module, 'bias'): 40 | nn.init.constant_(module.bias, bias) 41 | 42 | 43 | def bias_init_with_prob(prior_prob): 44 | """ initialize conv/fc bias value according to giving probablity""" 45 | bias_init = float(-np.log((1 - prior_prob) / prior_prob)) 46 | return bias_init 47 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/__init__.py: -------------------------------------------------------------------------------- 1 | from .dcn import (DeformConv, DeformConvPack, ModulatedDeformConv, 2 | ModulatedDeformConvPack, DeformRoIPooling, 3 | DeformRoIPoolingPack, ModulatedDeformRoIPoolingPack, 4 | deform_conv, modulated_deform_conv, deform_roi_pooling) 5 | from .gcb import ContextBlock 6 | from .nms import nms, soft_nms 7 | from .roi_align import RoIAlign, roi_align 8 | from .roi_pool import RoIPool, roi_pool 9 | from .sigmoid_focal_loss import SigmoidFocalLoss, sigmoid_focal_loss 10 | from .masked_conv import MaskedConv2d 11 | 12 | __all__ = [ 13 | 'nms', 'soft_nms', 'RoIAlign', 'roi_align', 'RoIPool', 'roi_pool', 14 | 'DeformConv', 'DeformConvPack', 'DeformRoIPooling', 'DeformRoIPoolingPack', 15 | 'ModulatedDeformRoIPoolingPack', 'ModulatedDeformConv', 16 | 'ModulatedDeformConvPack', 'deform_conv', 'modulated_deform_conv', 17 | 'deform_roi_pooling', 'SigmoidFocalLoss', 'sigmoid_focal_loss', 18 | 'MaskedConv2d', 'ContextBlock' 19 | ] 20 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/dcn/__init__.py: -------------------------------------------------------------------------------- 1 | from .functions.deform_conv import deform_conv, modulated_deform_conv 2 | from .functions.deform_pool import deform_roi_pooling 3 | from .modules.deform_conv import (DeformConv, ModulatedDeformConv, 4 | DeformConvPack, ModulatedDeformConvPack) 5 | from .modules.deform_pool import (DeformRoIPooling, DeformRoIPoolingPack, 6 | ModulatedDeformRoIPoolingPack) 7 | 8 | __all__ = [ 9 | 'DeformConv', 'DeformConvPack', 'ModulatedDeformConv', 10 | 'ModulatedDeformConvPack', 'DeformRoIPooling', 'DeformRoIPoolingPack', 11 | 'ModulatedDeformRoIPoolingPack', 'deform_conv', 'modulated_deform_conv', 12 | 'deform_roi_pooling' 13 | ] 14 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/dcn/functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/dcn/functions/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/dcn/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/dcn/modules/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/dcn/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 3 | 4 | setup( 5 | name='deform_conv', 6 | ext_modules=[ 7 | CUDAExtension('deform_conv_cuda', [ 8 | 'src/deform_conv_cuda.cpp', 9 | 'src/deform_conv_cuda_kernel.cu', 10 | ]), 11 | CUDAExtension( 12 | 'deform_pool_cuda', 13 | ['src/deform_pool_cuda.cpp', 'src/deform_pool_cuda_kernel.cu']), 14 | ], 15 | cmdclass={'build_ext': BuildExtension}) 16 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/gcb/__init__.py: -------------------------------------------------------------------------------- 1 | from .context_block import ContextBlock 2 | 3 | __all__ = [ 4 | 'ContextBlock', 5 | ] 6 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/kpts_nms/__init__.py: -------------------------------------------------------------------------------- 1 | from .nms_wrapper import kpts_nms 2 | 3 | __all__ = ['kpts_nms'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/kpts_nms/nms_wrapper.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | 4 | # from . import kpts_nms_cuda 5 | from . import kpts_nms_cpu 6 | 7 | 8 | def kpts_nms(kp_predictions, dets, iou_thr, device_id=None): 9 | """Dispatch to either CPU or GPU NMS implementations. 10 | 11 | The input can be either a torch tensor or numpy array. GPU NMS will be used 12 | if the input is a gpu tensor or device_id is specified, otherwise CPU NMS 13 | will be used. The returned type will always be the same as inputs. 14 | 15 | Arguments: 16 | dets (torch.Tensor or np.ndarray): bboxes with scores. 17 | iou_thr (float): IoU threshold for NMS. 18 | device_id (int, optional): when `dets` is a numpy array, if `device_id` 19 | is None, then cpu nms is used, otherwise gpu_nms will be used. 20 | 21 | Returns: 22 | tuple: kept bboxes and indice, which is always the same data type as 23 | the input. 24 | """ 25 | # convert dets (tensor or numpy array) to tensor 26 | if isinstance(dets, torch.Tensor): 27 | is_numpy = False 28 | dets_th = dets 29 | kp_predictions_th = kp_predictions 30 | elif isinstance(dets, np.ndarray): 31 | is_numpy = True 32 | device = 'cpu' if device_id is None else 'cuda:{}'.format(device_id) 33 | dets_th = torch.from_numpy(dets).to(device) 34 | kp_predictions_th = torch.from_numpy(kp_predictions).to(device) 35 | else: 36 | raise TypeError( 37 | 'dets must be either a Tensor or numpy array, but got {}'.format( 38 | type(dets))) 39 | 40 | # execute cpu or cuda nms 41 | if dets_th.shape[0] == 0: 42 | inds = dets_th.new_zeros(0, dtype=torch.long) 43 | else: 44 | """ 45 | if dets_th.is_cuda: 46 | inds = kpts_nms_cuda.nms(dets_th, iou_thr) 47 | else: 48 | inds = kpts_nms_cpu.nms(dets_th, iou_thr) 49 | """ 50 | # Current only support cpu version 51 | inds = kpts_nms_cpu.kpts_nms(kp_predictions_th, dets_th, iou_thr) 52 | if is_numpy: 53 | inds = inds.cpu().numpy() 54 | return dets[inds, :], inds -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/kpts_nms/src/kpts_nms_cuda.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #include 3 | 4 | #define CHECK_CUDA(x) AT_CHECK(x.type().is_cuda(), #x, " must be a CUDAtensor ") 5 | 6 | at::Tensor kpts_nms_cuda(const at::Tensor kp_predictions, const at::Tensor boxes, float kpts_nms_overlap_thresh); 7 | 8 | at::Tensor kpts_nms(const at::Tensor& kp_predictions, const at::Tensor& dets, const float threshold) { 9 | CHECK_CUDA(dets); 10 | CHECK_CUDA(kp_predictions); 11 | if (dets.numel() == 0) 12 | return at::empty({0}, dets.options().dtype(at::kLong).device(at::kCPU)); 13 | return kpts_nms_cuda(kp_predictions, dets, threshold); 14 | } 15 | 16 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 17 | m.def("kpts_nms", &nms, "non-maximum suppression"); 18 | } -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/masked_conv/__init__.py: -------------------------------------------------------------------------------- 1 | from .functions.masked_conv import masked_conv2d 2 | from .modules.masked_conv import MaskedConv2d 3 | 4 | __all__ = ['masked_conv2d', 'MaskedConv2d'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/masked_conv/functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/masked_conv/functions/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/masked_conv/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/masked_conv/modules/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/masked_conv/modules/masked_conv.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | from ..functions.masked_conv import masked_conv2d 3 | 4 | 5 | class MaskedConv2d(nn.Conv2d): 6 | """A MaskedConv2d which inherits the official Conv2d. 7 | 8 | The masked forward doesn't implement the backward function and only 9 | supports the stride parameter to be 1 currently. 10 | """ 11 | 12 | def __init__(self, 13 | in_channels, 14 | out_channels, 15 | kernel_size, 16 | stride=1, 17 | padding=0, 18 | dilation=1, 19 | groups=1, 20 | bias=True): 21 | super(MaskedConv2d, 22 | self).__init__(in_channels, out_channels, kernel_size, stride, 23 | padding, dilation, groups, bias) 24 | 25 | def forward(self, input, mask=None): 26 | if mask is None: # fallback to the normal Conv2d 27 | return super(MaskedConv2d, self).forward(input) 28 | else: 29 | return masked_conv2d(input, mask, self.weight, self.bias, 30 | self.padding) 31 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/masked_conv/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 3 | 4 | setup( 5 | name='masked_conv2d_cuda', 6 | ext_modules=[ 7 | CUDAExtension('masked_conv2d_cuda', [ 8 | 'src/masked_conv2d_cuda.cpp', 9 | 'src/masked_conv2d_kernel.cu', 10 | ]), 11 | ], 12 | cmdclass={'build_ext': BuildExtension}) 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/nms/__init__.py: -------------------------------------------------------------------------------- 1 | from .nms_wrapper import nms, soft_nms 2 | 3 | __all__ = ['nms', 'soft_nms'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/nms/src/nms_cuda.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 | #include 3 | 4 | #define CHECK_CUDA(x) AT_CHECK(x.type().is_cuda(), #x, " must be a CUDAtensor ") 5 | 6 | at::Tensor nms_cuda(const at::Tensor boxes, float nms_overlap_thresh); 7 | 8 | at::Tensor nms(const at::Tensor& dets, const float threshold) { 9 | CHECK_CUDA(dets); 10 | if (dets.numel() == 0) 11 | return at::empty({0}, dets.options().dtype(at::kLong).device(at::kCPU)); 12 | return nms_cuda(dets, threshold); 13 | } 14 | 15 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 16 | m.def("nms", &nms, "non-maximum suppression"); 17 | } -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/__init__.py: -------------------------------------------------------------------------------- 1 | from .functions.roi_align import roi_align 2 | from .modules.roi_align import RoIAlign 3 | 4 | __all__ = ['roi_align', 'RoIAlign'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/roi_align/functions/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/functions/roi_align.py: -------------------------------------------------------------------------------- 1 | from torch.autograd import Function 2 | 3 | from .. import roi_align_cuda 4 | 5 | 6 | class RoIAlignFunction(Function): 7 | 8 | @staticmethod 9 | def forward(ctx, features, rois, out_size, spatial_scale, sample_num=0): 10 | if isinstance(out_size, int): 11 | out_h = out_size 12 | out_w = out_size 13 | elif isinstance(out_size, tuple): 14 | assert len(out_size) == 2 15 | assert isinstance(out_size[0], int) 16 | assert isinstance(out_size[1], int) 17 | out_h, out_w = out_size 18 | else: 19 | raise TypeError( 20 | '"out_size" must be an integer or tuple of integers') 21 | ctx.spatial_scale = spatial_scale 22 | ctx.sample_num = sample_num 23 | ctx.save_for_backward(rois) 24 | ctx.feature_size = features.size() 25 | 26 | batch_size, num_channels, data_height, data_width = features.size() 27 | num_rois = rois.size(0) 28 | 29 | output = features.new_zeros(num_rois, num_channels, out_h, out_w) 30 | if features.is_cuda: 31 | roi_align_cuda.forward(features, rois, out_h, out_w, spatial_scale, 32 | sample_num, output) 33 | else: 34 | raise NotImplementedError 35 | 36 | return output 37 | 38 | @staticmethod 39 | def backward(ctx, grad_output): 40 | feature_size = ctx.feature_size 41 | spatial_scale = ctx.spatial_scale 42 | sample_num = ctx.sample_num 43 | rois = ctx.saved_tensors[0] 44 | assert (feature_size is not None and grad_output.is_cuda) 45 | 46 | batch_size, num_channels, data_height, data_width = feature_size 47 | out_w = grad_output.size(3) 48 | out_h = grad_output.size(2) 49 | 50 | grad_input = grad_rois = None 51 | if ctx.needs_input_grad[0]: 52 | grad_input = rois.new_zeros(batch_size, num_channels, data_height, 53 | data_width) 54 | roi_align_cuda.backward(grad_output.contiguous(), rois, out_h, 55 | out_w, spatial_scale, sample_num, 56 | grad_input) 57 | 58 | return grad_input, grad_rois, None, None, None 59 | 60 | 61 | roi_align = RoIAlignFunction.apply 62 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/gradcheck.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch.autograd import gradcheck 4 | 5 | import os.path as osp 6 | import sys 7 | sys.path.append(osp.abspath(osp.join(__file__, '../../'))) 8 | from roi_align import RoIAlign # noqa: E402 9 | 10 | feat_size = 15 11 | spatial_scale = 1.0 / 8 12 | img_size = feat_size / spatial_scale 13 | num_imgs = 2 14 | num_rois = 20 15 | 16 | batch_ind = np.random.randint(num_imgs, size=(num_rois, 1)) 17 | rois = np.random.rand(num_rois, 4) * img_size * 0.5 18 | rois[:, 2:] += img_size * 0.5 19 | rois = np.hstack((batch_ind, rois)) 20 | 21 | feat = torch.randn( 22 | num_imgs, 16, feat_size, feat_size, requires_grad=True, device='cuda:0') 23 | rois = torch.from_numpy(rois).float().cuda() 24 | inputs = (feat, rois) 25 | print('Gradcheck for roi align...') 26 | test = gradcheck(RoIAlign(3, spatial_scale), inputs, atol=1e-3, eps=1e-3) 27 | print(test) 28 | test = gradcheck(RoIAlign(3, spatial_scale, 2), inputs, atol=1e-3, eps=1e-3) 29 | print(test) 30 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/roi_align/modules/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/modules/roi_align.py: -------------------------------------------------------------------------------- 1 | from torch.nn.modules.module import Module 2 | from ..functions.roi_align import RoIAlignFunction 3 | 4 | 5 | class RoIAlign(Module): 6 | 7 | def __init__(self, out_size, spatial_scale, sample_num=0): 8 | super(RoIAlign, self).__init__() 9 | 10 | self.out_size = out_size 11 | self.spatial_scale = float(spatial_scale) 12 | self.sample_num = int(sample_num) 13 | 14 | def forward(self, features, rois): 15 | return RoIAlignFunction.apply(features, rois, self.out_size, 16 | self.spatial_scale, self.sample_num) 17 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_align/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 3 | 4 | setup( 5 | name='roi_align_cuda', 6 | ext_modules=[ 7 | CUDAExtension('roi_align_cuda', [ 8 | 'src/roi_align_cuda.cpp', 9 | 'src/roi_align_kernel.cu', 10 | ]), 11 | ], 12 | cmdclass={'build_ext': BuildExtension}) 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/__init__.py: -------------------------------------------------------------------------------- 1 | from .functions.roi_pool import roi_pool 2 | from .modules.roi_pool import RoIPool 3 | 4 | __all__ = ['roi_pool', 'RoIPool'] 5 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/roi_pool/functions/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/functions/roi_pool.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.autograd import Function 3 | 4 | from .. import roi_pool_cuda 5 | 6 | 7 | class RoIPoolFunction(Function): 8 | 9 | @staticmethod 10 | def forward(ctx, features, rois, out_size, spatial_scale): 11 | if isinstance(out_size, int): 12 | out_h = out_size 13 | out_w = out_size 14 | elif isinstance(out_size, tuple): 15 | assert len(out_size) == 2 16 | assert isinstance(out_size[0], int) 17 | assert isinstance(out_size[1], int) 18 | out_h, out_w = out_size 19 | else: 20 | raise TypeError( 21 | '"out_size" must be an integer or tuple of integers') 22 | assert features.is_cuda 23 | ctx.save_for_backward(rois) 24 | num_channels = features.size(1) 25 | num_rois = rois.size(0) 26 | out_size = (num_rois, num_channels, out_h, out_w) 27 | output = features.new_zeros(out_size) 28 | argmax = features.new_zeros(out_size, dtype=torch.int) 29 | roi_pool_cuda.forward(features, rois, out_h, out_w, spatial_scale, 30 | output, argmax) 31 | ctx.spatial_scale = spatial_scale 32 | ctx.feature_size = features.size() 33 | ctx.argmax = argmax 34 | 35 | return output 36 | 37 | @staticmethod 38 | def backward(ctx, grad_output): 39 | assert grad_output.is_cuda 40 | spatial_scale = ctx.spatial_scale 41 | feature_size = ctx.feature_size 42 | argmax = ctx.argmax 43 | rois = ctx.saved_tensors[0] 44 | assert feature_size is not None 45 | 46 | grad_input = grad_rois = None 47 | if ctx.needs_input_grad[0]: 48 | grad_input = grad_output.new_zeros(feature_size) 49 | roi_pool_cuda.backward(grad_output.contiguous(), rois, argmax, 50 | spatial_scale, grad_input) 51 | 52 | return grad_input, grad_rois, None, None 53 | 54 | 55 | roi_pool = RoIPoolFunction.apply 56 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/gradcheck.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.autograd import gradcheck 3 | 4 | import os.path as osp 5 | import sys 6 | sys.path.append(osp.abspath(osp.join(__file__, '../../'))) 7 | from roi_pool import RoIPool # noqa: E402 8 | 9 | feat = torch.randn(4, 16, 15, 15, requires_grad=True).cuda() 10 | rois = torch.Tensor([[0, 0, 0, 50, 50], [0, 10, 30, 43, 55], 11 | [1, 67, 40, 110, 120]]).cuda() 12 | inputs = (feat, rois) 13 | print('Gradcheck for roi pooling...') 14 | test = gradcheck(RoIPool(4, 1.0 / 8), inputs, eps=1e-5, atol=1e-3) 15 | print(test) 16 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/roi_pool/modules/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/modules/roi_pool.py: -------------------------------------------------------------------------------- 1 | from torch.nn.modules.module import Module 2 | from ..functions.roi_pool import roi_pool 3 | 4 | 5 | class RoIPool(Module): 6 | 7 | def __init__(self, out_size, spatial_scale): 8 | super(RoIPool, self).__init__() 9 | 10 | self.out_size = out_size 11 | self.spatial_scale = float(spatial_scale) 12 | 13 | def forward(self, features, rois): 14 | return roi_pool(features, rois, self.out_size, self.spatial_scale) 15 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/roi_pool/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 3 | 4 | setup( 5 | name='roi_pool', 6 | ext_modules=[ 7 | CUDAExtension('roi_pool_cuda', [ 8 | 'src/roi_pool_cuda.cpp', 9 | 'src/roi_pool_kernel.cu', 10 | ]) 11 | ], 12 | cmdclass={'build_ext': BuildExtension}) 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/__init__.py: -------------------------------------------------------------------------------- 1 | from .modules.sigmoid_focal_loss import SigmoidFocalLoss, sigmoid_focal_loss 2 | 3 | __all__ = ['SigmoidFocalLoss', 'sigmoid_focal_loss'] 4 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/sigmoid_focal_loss/functions/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/functions/sigmoid_focal_loss.py: -------------------------------------------------------------------------------- 1 | from torch.autograd import Function 2 | from torch.autograd.function import once_differentiable 3 | 4 | from .. import sigmoid_focal_loss_cuda 5 | 6 | 7 | class SigmoidFocalLossFunction(Function): 8 | 9 | @staticmethod 10 | def forward(ctx, input, target, gamma=2.0, alpha=0.25): 11 | ctx.save_for_backward(input, target) 12 | num_classes = input.shape[1] 13 | ctx.num_classes = num_classes 14 | ctx.gamma = gamma 15 | ctx.alpha = alpha 16 | 17 | loss = sigmoid_focal_loss_cuda.forward(input, target, num_classes, 18 | gamma, alpha) 19 | return loss 20 | 21 | @staticmethod 22 | @once_differentiable 23 | def backward(ctx, d_loss): 24 | input, target = ctx.saved_tensors 25 | num_classes = ctx.num_classes 26 | gamma = ctx.gamma 27 | alpha = ctx.alpha 28 | d_loss = d_loss.contiguous() 29 | d_input = sigmoid_focal_loss_cuda.backward(input, target, d_loss, 30 | num_classes, gamma, alpha) 31 | return d_input, None, None, None, None 32 | 33 | 34 | sigmoid_focal_loss = SigmoidFocalLossFunction.apply 35 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/mmdetection/mmdet/ops/sigmoid_focal_loss/modules/__init__.py -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/modules/sigmoid_focal_loss.py: -------------------------------------------------------------------------------- 1 | from torch import nn 2 | 3 | from ..functions.sigmoid_focal_loss import sigmoid_focal_loss 4 | 5 | 6 | # TODO: remove this module 7 | class SigmoidFocalLoss(nn.Module): 8 | 9 | def __init__(self, gamma, alpha): 10 | super(SigmoidFocalLoss, self).__init__() 11 | self.gamma = gamma 12 | self.alpha = alpha 13 | 14 | def forward(self, logits, targets): 15 | assert logits.is_cuda 16 | loss = sigmoid_focal_loss(logits, targets, self.gamma, self.alpha) 17 | return loss.sum() 18 | 19 | def __repr__(self): 20 | tmpstr = self.__class__.__name__ + "(" 21 | tmpstr += "gamma=" + str(self.gamma) 22 | tmpstr += ", alpha=" + str(self.alpha) 23 | tmpstr += ")" 24 | return tmpstr 25 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 3 | 4 | setup( 5 | name='SigmoidFocalLoss', 6 | ext_modules=[ 7 | CUDAExtension('sigmoid_focal_loss_cuda', [ 8 | 'src/sigmoid_focal_loss.cpp', 9 | 'src/sigmoid_focal_loss_cuda.cu', 10 | ]), 11 | ], 12 | cmdclass={'build_ext': BuildExtension}) 13 | -------------------------------------------------------------------------------- /mmdetection/mmdet/ops/sigmoid_focal_loss/src/sigmoid_focal_loss.cpp: -------------------------------------------------------------------------------- 1 | // modify from 2 | // https://github.com/facebookresearch/maskrcnn-benchmark/blob/master/maskrcnn_benchmark/csrc/SigmoidFocalLoss.h 3 | #include 4 | 5 | at::Tensor SigmoidFocalLoss_forward_cuda(const at::Tensor &logits, 6 | const at::Tensor &targets, 7 | const int num_classes, 8 | const float gamma, const float alpha); 9 | 10 | at::Tensor SigmoidFocalLoss_backward_cuda(const at::Tensor &logits, 11 | const at::Tensor &targets, 12 | const at::Tensor &d_losses, 13 | const int num_classes, 14 | const float gamma, const float alpha); 15 | 16 | // Interface for Python 17 | at::Tensor SigmoidFocalLoss_forward(const at::Tensor &logits, 18 | const at::Tensor &targets, 19 | const int num_classes, const float gamma, 20 | const float alpha) { 21 | if (logits.type().is_cuda()) { 22 | return SigmoidFocalLoss_forward_cuda(logits, targets, num_classes, gamma, 23 | alpha); 24 | } 25 | } 26 | 27 | at::Tensor SigmoidFocalLoss_backward(const at::Tensor &logits, 28 | const at::Tensor &targets, 29 | const at::Tensor &d_losses, 30 | const int num_classes, const float gamma, 31 | const float alpha) { 32 | if (logits.type().is_cuda()) { 33 | return SigmoidFocalLoss_backward_cuda(logits, targets, d_losses, 34 | num_classes, gamma, alpha); 35 | } 36 | } 37 | 38 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 39 | m.def("forward", &SigmoidFocalLoss_forward, 40 | "SigmoidFocalLoss forward (CUDA)"); 41 | m.def("backward", &SigmoidFocalLoss_backward, 42 | "SigmoidFocalLoss backward (CUDA)"); 43 | } 44 | -------------------------------------------------------------------------------- /mmdetection/mmdet/version.py: -------------------------------------------------------------------------------- 1 | # GENERATED VERSION FILE 2 | # TIME: Mon Sep 21 22:56:55 2020 3 | 4 | __version__ = '0.6.0+5fc16cb' 5 | short_version = '0.6.0' 6 | -------------------------------------------------------------------------------- /mmdetection/scripts/demo.sh: -------------------------------------------------------------------------------- 1 | python3 tools/demo.py --config=configs/bmp/finetune.py --image_folder=demo_images/ --output_folder=results/ --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_all.sh: -------------------------------------------------------------------------------- 1 | python3 tools/eval_all.py configs/bmp/finetune.py --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_haggling.sh: -------------------------------------------------------------------------------- 1 | python3 tools/full_eval.py configs/bmp/finetune.py haggling --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_mafia.sh: -------------------------------------------------------------------------------- 1 | python3 tools/full_eval.py configs/bmp/finetune.py mafia --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_mupots.sh: -------------------------------------------------------------------------------- 1 | python3 tools/full_eval.py configs/bmp/finetune.py mupots --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_pizza.sh: -------------------------------------------------------------------------------- 1 | python3 tools/full_eval.py configs/bmp/finetune.py pizza --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_pw3d.sh: -------------------------------------------------------------------------------- 1 | python3 tools/full_eval.py configs/bmp/finetune.py pw3d --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/eval_ultimatum.sh: -------------------------------------------------------------------------------- 1 | python3 tools/full_eval.py configs/bmp/finetune.py ultimatum --ckpt ./work_dirs/finetune/latest.pth -------------------------------------------------------------------------------- /mmdetection/scripts/finetune.sh: -------------------------------------------------------------------------------- 1 | while true 2 | do 3 | python3 tools/train.py configs/bmp/finetune.py --gpus 8 4 | done -------------------------------------------------------------------------------- /mmdetection/scripts/pretrain.sh: -------------------------------------------------------------------------------- 1 | while true 2 | do 3 | python3 tools/train.py configs/bmp/pretrain.py --gpus 8 4 | done 5 | 6 | -------------------------------------------------------------------------------- /neural_renderer/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hiroharu Kato 4 | Copyright (c) 2018 Nikos Kolotouros 5 | A PyTorch implementation of Neural 3D Mesh Renderer (https://github.com/hiroharu-kato/neural_renderer) 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /neural_renderer/examples/example1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example 1. Drawing a teapot from multiple viewpoints. 3 | """ 4 | import os 5 | import argparse 6 | 7 | import torch 8 | import numpy as np 9 | import tqdm 10 | import imageio 11 | 12 | import neural_renderer as nr 13 | 14 | current_dir = os.path.dirname(os.path.realpath(__file__)) 15 | data_dir = os.path.join(current_dir, 'data') 16 | 17 | 18 | def main(): 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('-i', '--filename_input', type=str, default=os.path.join(data_dir, 'teapot.obj')) 21 | parser.add_argument('-o', '--filename_output', type=str, default=os.path.join(data_dir, 'example1.gif')) 22 | parser.add_argument('-g', '--gpu', type=int, default=0) 23 | args = parser.parse_args() 24 | 25 | # other settings 26 | camera_distance = 2.732 27 | elevation = 30 28 | texture_size = 2 29 | 30 | # load .obj 31 | vertices, faces = nr.load_obj(args.filename_input) 32 | vertices = vertices[None, :, :] # [num_vertices, XYZ] -> [batch_size=1, num_vertices, XYZ] 33 | faces = faces[None, :, :] # [num_faces, 3] -> [batch_size=1, num_faces, 3] 34 | 35 | # create texture [batch_size=1, num_faces, texture_size, texture_size, texture_size, RGB] 36 | textures = torch.ones(1, faces.shape[1], texture_size, texture_size, texture_size, 3, dtype=torch.float32).cuda() 37 | 38 | # to gpu 39 | 40 | # create renderer 41 | renderer = nr.Renderer(camera_mode='look_at') 42 | 43 | # draw object 44 | loop = tqdm.tqdm(range(0, 360, 4)) 45 | writer = imageio.get_writer(args.filename_output, mode='I') 46 | for num, azimuth in enumerate(loop): 47 | loop.set_description('Drawing') 48 | renderer.eye = nr.get_points_from_angles(camera_distance, elevation, azimuth) 49 | images, _, _ = renderer(vertices, faces, textures) # [batch_size, RGB, image_size, image_size] 50 | image = images.detach().cpu().numpy()[0].transpose((1, 2, 0)) # [image_size, image_size, RGB] 51 | writer.append_data((255*image).astype(np.uint8)) 52 | writer.close() 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/__init__.py: -------------------------------------------------------------------------------- 1 | from .get_points_from_angles import get_points_from_angles 2 | from .lighting import lighting 3 | from .load_obj import load_obj 4 | from .look import look 5 | from .look_at import look_at 6 | from .mesh import Mesh 7 | from .perspective import perspective 8 | from .projection import projection 9 | from .rasterize import (rasterize_rgbad, rasterize, rasterize_silhouettes, rasterize_depth, Rasterize) 10 | from .renderer import Renderer 11 | from .save_obj import save_obj 12 | from .vertices_to_faces import vertices_to_faces 13 | from .visibility import face_visibility 14 | 15 | __version__ = '1.1.3' 16 | name = 'neural_renderer_pytorch' 17 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/cuda/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/neural_renderer/neural_renderer/cuda/__init__.py -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/cuda/create_texture_image_cuda.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // CUDA forward declarations 4 | 5 | at::Tensor create_texture_image_cuda( 6 | at::Tensor vertices_all, 7 | at::Tensor textures, 8 | at::Tensor image, 9 | float eps); 10 | 11 | // C++ interface 12 | 13 | #define CHECK_CUDA(x) AT_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") 14 | #define CHECK_CONTIGUOUS(x) AT_CHECK(x.is_contiguous(), #x " must be contiguous") 15 | #define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) 16 | 17 | 18 | at::Tensor create_texture_image( 19 | at::Tensor vertices_all, 20 | at::Tensor textures, 21 | at::Tensor image, 22 | float eps) { 23 | 24 | CHECK_INPUT(vertices_all); 25 | CHECK_INPUT(textures); 26 | CHECK_INPUT(image); 27 | 28 | return create_texture_image_cuda(vertices_all, textures, image, eps); 29 | } 30 | 31 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 32 | m.def("create_texture_image", &create_texture_image, "CREATE_TEXTURE_IMAGE (CUDA)"); 33 | } 34 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/cuda/load_textures_cuda.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // CUDA forward declarations 4 | 5 | at::Tensor load_textures_cuda( 6 | at::Tensor image, 7 | at::Tensor faces, 8 | at::Tensor textures, 9 | at::Tensor is_update, 10 | int texture_wrapping, 11 | int use_bilinear); 12 | 13 | // C++ interface 14 | 15 | #define CHECK_CUDA(x) AT_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") 16 | #define CHECK_CONTIGUOUS(x) AT_CHECK(x.is_contiguous(), #x " must be contiguous") 17 | #define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) 18 | 19 | 20 | at::Tensor load_textures( 21 | at::Tensor image, 22 | at::Tensor faces, 23 | at::Tensor textures, 24 | at::Tensor is_update, 25 | int texture_wrapping, 26 | int use_bilinear) { 27 | 28 | CHECK_INPUT(image); 29 | CHECK_INPUT(faces); 30 | CHECK_INPUT(is_update); 31 | CHECK_INPUT(textures); 32 | 33 | return load_textures_cuda(image, faces, textures, is_update, texture_wrapping, use_bilinear); 34 | 35 | } 36 | 37 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 38 | m.def("load_textures", &load_textures, "LOAD_TEXTURES (CUDA)"); 39 | } 40 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/get_points_from_angles.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import math 3 | 4 | import torch 5 | 6 | def get_points_from_angles(distance, elevation, azimuth, degrees=True): 7 | if isinstance(distance, float) or isinstance(distance, int): 8 | if degrees: 9 | elevation = math.radians(elevation) 10 | azimuth = math.radians(azimuth) 11 | return ( 12 | distance * math.cos(elevation) * math.sin(azimuth), 13 | distance * math.sin(elevation), 14 | -distance * math.cos(elevation) * math.cos(azimuth)) 15 | else: 16 | if degrees: 17 | elevation = math.pi/180. * elevation 18 | azimuth = math.pi/180. * azimuth 19 | # 20 | return torch.stack([ 21 | distance * torch.cos(elevation) * torch.sin(azimuth), 22 | distance * torch.sin(elevation), 23 | -distance * torch.cos(elevation) * torch.cos(azimuth) 24 | ]).transpose(1,0) 25 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/look.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn.functional as F 4 | 5 | 6 | def look(vertices, eye, direction=[0, 1, 0], up=None): 7 | """ 8 | "Look" transformation of vertices. 9 | """ 10 | if (vertices.ndimension() != 3): 11 | raise ValueError('vertices Tensor should have 3 dimensions') 12 | 13 | device = vertices.device 14 | 15 | if isinstance(direction, list) or isinstance(direction, tuple): 16 | direction = torch.tensor(direction, dtype=torch.float32, device=device) 17 | elif isinstance(direction, np.ndarray): 18 | direction = torch.from_numpy(direction).to(device) 19 | elif torch.is_tensor(direction): 20 | direction = direction.to(device) 21 | 22 | if isinstance(eye, list) or isinstance(eye, tuple): 23 | eye = torch.tensor(eye, dtype=torch.float32, device=device) 24 | elif isinstance(eye, np.ndarray): 25 | eye = torch.from_numpy(eye).to(device) 26 | elif torch.is_tensor(eye): 27 | eye = eye.to(device) 28 | 29 | if up is None: 30 | up = torch.cuda.FloatTensor([0, 1, 0]) 31 | if eye.ndimension() == 1: 32 | eye = eye[None, :] 33 | if direction.ndimension() == 1: 34 | direction = direction[None, :] 35 | if up.ndimension() == 1: 36 | up = up[None, :] 37 | 38 | # create new axes 39 | z_axis = F.normalize(direction, eps=1e-5) 40 | x_axis = F.normalize(torch.cross(up, z_axis), eps=1e-5) 41 | y_axis = F.normalize(torch.cross(z_axis, x_axis), eps=1e-5) 42 | 43 | # create rotation matrix: [bs, 3, 3] 44 | r = torch.cat((x_axis[:, None, :], y_axis[:, None, :], z_axis[:, None, :]), dim=1) 45 | 46 | # apply 47 | # [bs, nv, 3] -> [bs, nv, 3] -> [bs, nv, 3] 48 | if vertices.shape != eye.shape: 49 | eye = eye[:, None, :] 50 | vertices = vertices - eye 51 | vertices = torch.matmul(vertices, r.transpose(1,2)) 52 | 53 | return vertices 54 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/look_at.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn.functional as F 4 | 5 | 6 | def look_at(vertices, eye, at=[0, 0, 0], up=[0, 1, 0]): 7 | """ 8 | "Look at" transformation of vertices. 9 | """ 10 | if (vertices.ndimension() != 3): 11 | raise ValueError('vertices Tensor should have 3 dimensions') 12 | 13 | device = vertices.device 14 | 15 | # if list or tuple convert to numpy array 16 | if isinstance(at, list) or isinstance(at, tuple): 17 | at = torch.tensor(at, dtype=torch.float32, device=device) 18 | # if numpy array convert to tensor 19 | elif isinstance(at, np.ndarray): 20 | at = torch.from_numpy(at).to(device) 21 | elif torch.is_tensor(at): 22 | at.to(device) 23 | 24 | if isinstance(up, list) or isinstance(up, tuple): 25 | up = torch.tensor(up, dtype=torch.float32, device=device) 26 | elif isinstance(up, np.ndarray): 27 | up = torch.from_numpy(up).to(device) 28 | elif torch.is_tensor(up): 29 | up.to(device) 30 | 31 | if isinstance(eye, list) or isinstance(eye, tuple): 32 | eye = torch.tensor(eye, dtype=torch.float32, device=device) 33 | elif isinstance(eye, np.ndarray): 34 | eye = torch.from_numpy(eye).to(device) 35 | elif torch.is_tensor(eye): 36 | eye = eye.to(device) 37 | 38 | batch_size = vertices.shape[0] 39 | if eye.ndimension() == 1: 40 | eye = eye[None, :].repeat(batch_size, 1) 41 | if at.ndimension() == 1: 42 | at = at[None, :].repeat(batch_size, 1) 43 | if up.ndimension() == 1: 44 | up = up[None, :].repeat(batch_size, 1) 45 | 46 | # create new axes 47 | # eps is chosen as 0.5 to match the chainer version 48 | z_axis = F.normalize(at - eye, eps=1e-5) 49 | x_axis = F.normalize(torch.cross(up, z_axis), eps=1e-5) 50 | y_axis = F.normalize(torch.cross(z_axis, x_axis), eps=1e-5) 51 | 52 | # create rotation matrix: [bs, 3, 3] 53 | r = torch.cat((x_axis[:, None, :], y_axis[:, None, :], z_axis[:, None, :]), dim=1) 54 | 55 | # apply 56 | # [bs, nv, 3] -> [bs, nv, 3] -> [bs, nv, 3] 57 | if vertices.shape != eye.shape: 58 | eye = eye[:, None, :] 59 | vertices = vertices - eye 60 | vertices = torch.matmul(vertices, r.transpose(1,2)) 61 | 62 | return vertices 63 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/mesh.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | import neural_renderer as nr 5 | 6 | class Mesh(object): 7 | ''' 8 | A simple class for creating and manipulating trimesh objects 9 | ''' 10 | def __init__(self, vertices, faces, textures=None, texture_size=4): 11 | ''' 12 | vertices, faces and textures(if not None) are expected to be Tensor objects 13 | ''' 14 | self.vertices = vertices 15 | self.faces = faces 16 | self.num_vertices = self.vertices.shape[0] 17 | self.num_faces = self.faces.shape[0] 18 | 19 | # create textures 20 | if textures is None: 21 | shape = (self.num_faces, texture_size, texture_size, texture_size, 3) 22 | self.textures = nn.Parameter(0.05*torch.randn(*shape)) 23 | self.texture_size = texture_size 24 | else: 25 | self.texture_size = textures.shape[0] 26 | 27 | @classmethod 28 | def fromobj(cls, filename_obj, normalization=True, load_texture=False, texture_size=4): 29 | ''' 30 | Create a Mesh object from a .obj file 31 | ''' 32 | if load_texture: 33 | vertices, faces, textures = nr.load_obj(filename_obj, 34 | normalization=normalization, 35 | texture_size=texture_size, 36 | load_texture=True) 37 | else: 38 | vertices, faces = nr.load_obj(filename_obj, 39 | normalization=normalization, 40 | texture_size=texture_size, 41 | load_texture=False) 42 | textures = None 43 | return cls(vertices, faces, textures, texture_size) 44 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/perspective.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import math 3 | 4 | import torch 5 | 6 | def perspective(vertices, angle=30.): 7 | ''' 8 | Compute perspective distortion from a given angle 9 | ''' 10 | if (vertices.ndimension() != 3): 11 | raise ValueError('vertices Tensor should have 3 dimensions') 12 | device = vertices.device 13 | angle = torch.tensor(angle / 180 * math.pi, dtype=torch.float32, device=device) 14 | angle = angle[None] 15 | width = torch.tan(angle) 16 | width = width[:, None] 17 | z = vertices[:, :, 2] 18 | x = vertices[:, :, 0] / z / width 19 | y = vertices[:, :, 1] / z / width 20 | vertices = torch.stack((x,y,z), dim=2) 21 | return vertices 22 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/projection.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | import torch 4 | 5 | 6 | def projection(vertices, K, R, t, dist_coeffs, orig_size, eps=1e-9): 7 | ''' 8 | Calculate projective transformation of vertices given a projection matrix 9 | Input parameters: 10 | K: batch_size * 3 * 3 intrinsic camera matrix 11 | R, t: batch_size * 3 * 3, batch_size * 1 * 3 extrinsic calibration parameters 12 | dist_coeffs: vector of distortion coefficients 13 | orig_size: original size of image captured by the camera 14 | Returns: For each point [X,Y,Z] in world coordinates [u,v,z] where u,v are the coordinates of the projection in 15 | pixels and z is the depth 16 | ''' 17 | 18 | # instead of P*x we compute x'*P' 19 | vertices = torch.matmul(vertices, R.transpose(2,1)) + t 20 | x, y, z = vertices[:, :, 0], vertices[:, :, 1], vertices[:, :, 2] 21 | x_ = x / (z + eps) 22 | y_ = y / (z + eps) 23 | 24 | # Get distortion coefficients from vector 25 | k1 = dist_coeffs[:, None, 0] 26 | k2 = dist_coeffs[:, None, 1] 27 | p1 = dist_coeffs[:, None, 2] 28 | p2 = dist_coeffs[:, None, 3] 29 | k3 = dist_coeffs[:, None, 4] 30 | 31 | # we use x_ for x' and x__ for x'' etc. 32 | r = torch.sqrt(x_ ** 2 + y_ ** 2) 33 | x__ = x_*(1 + k1*(r**2) + k2*(r**4) + k3*(r**6)) + 2*p1*x_*y_ + p2*(r**2 + 2*x_**2) 34 | y__ = y_*(1 + k1*(r**2) + k2*(r**4) + k3 *(r**6)) + p1*(r**2 + 2*y_**2) + 2*p2*x_*y_ 35 | vertices = torch.stack([x__, y__, torch.ones_like(z)], dim=-1) 36 | vertices = torch.matmul(vertices, K.transpose(1,2)) 37 | u, v = vertices[:, :, 0], vertices[:, :, 1] 38 | v = orig_size - v 39 | # map u,v from [0, img_size] to [-1, 1] to use by the renderer 40 | u = 2 * (u - orig_size / 2.) / orig_size 41 | v = 2 * (v - orig_size / 2.) / orig_size 42 | vertices = torch.stack([u, v, z], dim=-1) 43 | return vertices 44 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/vertices_to_faces.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | def vertices_to_faces(vertices, faces): 5 | """ 6 | :param vertices: [batch size, number of vertices, 3] 7 | :param faces: [batch size, number of faces, 3) 8 | :return: [batch size, number of faces, 3, 3] 9 | """ 10 | assert (vertices.ndimension() == 3) 11 | assert (faces.ndimension() == 3) 12 | assert (vertices.shape[0] == faces.shape[0]) 13 | assert (vertices.shape[2] == 3) 14 | assert (faces.shape[2] == 3) 15 | 16 | bs, nv = vertices.shape[:2] 17 | bs, nf = faces.shape[:2] 18 | device = vertices.device 19 | faces = faces + (torch.arange(bs, dtype=torch.int32).to(device) * nv)[:, None, None] 20 | vertices = vertices.reshape((bs * nv, 3)) 21 | # pytorch only supports long and byte tensors for indexing 22 | return vertices[faces.long()] 23 | -------------------------------------------------------------------------------- /neural_renderer/neural_renderer/visibility.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import neural_renderer.cuda.rasterize as rasterize_cuda 3 | import time 4 | 5 | DEFAULT_IMAGE_SIZE = 256 6 | DEFAULT_ANTI_ALIASING = True 7 | DEFAULT_NEAR = 0.1 8 | DEFAULT_FAR = 100 9 | DEFAULT_EPS = 1e-4 10 | DEFAULT_BACKGROUND_COLOR = (0, 0, 0) 11 | 12 | def face_visibility(faces, image_size, near=DEFAULT_NEAR, far=DEFAULT_FAR, eps=DEFAULT_EPS): 13 | 14 | batch_size = faces.shape[0] 15 | face_index_map = torch.cuda.IntTensor(batch_size, image_size, image_size).fill_(-1) 16 | weight_map = torch.cuda.FloatTensor(batch_size, image_size, image_size, 3).fill_(0.0) 17 | depth_map = torch.cuda.FloatTensor(batch_size, image_size, image_size).fill_(far) 18 | rgb_map = torch.cuda.FloatTensor(1).fill_(0) 19 | face_inv_map = torch.cuda.FloatTensor(1).fill_(0) 20 | num_faces = faces.shape[1] 21 | block_size = 4 22 | buffer_size = 512 23 | face_visibility = torch.cuda.IntTensor(batch_size, num_faces).fill_(0) 24 | face_list = torch.cuda.IntTensor(batch_size, (image_size-1)//block_size+1, (image_size-1)//block_size+1, buffer_size).fill_(0) 25 | faces_inv = torch.zeros_like(faces) 26 | # tstart = time.time() 27 | _, _, _, _, face_visibility = rasterize_cuda.forward_face_index_map(faces, face_index_map, weight_map, 28 | depth_map, face_inv_map, faces_inv, face_visibility, 29 | face_list, 30 | image_size, block_size, near, far, 31 | False, False, 32 | False, True) 33 | 34 | return face_visibility 35 | -------------------------------------------------------------------------------- /neural_renderer/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | import unittest 3 | 4 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 5 | 6 | CUDA_FLAGS = [] 7 | INSTALL_REQUIREMENTS = [] 8 | 9 | def test_all(): 10 | test_loader = unittest.TestLoader() 11 | test_suite = test_loader.discover('tests', pattern='test_*.py') 12 | return test_suite 13 | 14 | ext_modules=[ 15 | CUDAExtension('neural_renderer.cuda.load_textures', [ 16 | 'neural_renderer/cuda/load_textures_cuda.cpp', 17 | 'neural_renderer/cuda/load_textures_cuda_kernel.cu', 18 | ]), 19 | CUDAExtension('neural_renderer.cuda.rasterize', [ 20 | 'neural_renderer/cuda/rasterize_cuda.cpp', 21 | 'neural_renderer/cuda/rasterize_cuda_kernel.cu', 22 | ]), 23 | CUDAExtension('neural_renderer.cuda.create_texture_image', [ 24 | 'neural_renderer/cuda/create_texture_image_cuda.cpp', 25 | 'neural_renderer/cuda/create_texture_image_cuda_kernel.cu', 26 | ]), 27 | ] 28 | 29 | setup( 30 | description='PyTorch implementation of "A 3D mesh renderer for neural networks"', 31 | author='Nikolaos Kolotouros', 32 | author_email='nkolot@seas.upenn.edu', 33 | license='MIT License', 34 | version='1.1.3', 35 | name='neural_renderer_pytorch', 36 | test_suite='setup.test_all', 37 | packages=['neural_renderer', 'neural_renderer.cuda'], 38 | install_requires=INSTALL_REQUIREMENTS, 39 | ext_modules=ext_modules, 40 | cmdclass = {'build_ext': BuildExtension} 41 | ) 42 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_get_points_from_angles.py: -------------------------------------------------------------------------------- 1 | # TODO 2 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_lighting.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import torch 4 | 5 | import neural_renderer as nr 6 | 7 | class TestLighting(unittest.TestCase): 8 | 9 | def test_case1(self): 10 | """Test whether it is executable.""" 11 | faces = torch.randn(64, 16, 3, 3, dtype=torch.float32) 12 | textures = torch.randn(64, 16, 8, 8, 8, 3, dtype=torch.float32) 13 | nr.lighting(faces, textures) 14 | 15 | if __name__ == '__main__': 16 | unittest.main() 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_look.py: -------------------------------------------------------------------------------- 1 | # TODO 2 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_look_at.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import torch 4 | import numpy as np 5 | 6 | import neural_renderer as nr 7 | 8 | class TestLookAt(unittest.TestCase): 9 | def test_case1(self): 10 | eyes = [ 11 | [1, 0, 1], 12 | [0, 0, -10], 13 | [-1, 1, 0], 14 | ] 15 | answers = [ 16 | [-np.sqrt(2) / 2, 0, np.sqrt(2) / 2], 17 | [1, 0, 10], 18 | [0, np.sqrt(2) / 2, 3. / 2. * np.sqrt(2)], 19 | ] 20 | vertices = torch.from_numpy(np.array([1, 0, 0], np.float32)) 21 | vertices = vertices[None, None, :] 22 | for e, a in zip(eyes, answers): 23 | eye = np.array(e, np.float32) 24 | transformed = nr.look_at(vertices, eye) 25 | assert(np.allclose(transformed.data.squeeze().numpy(), np.array(a))) 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_perspective.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import torch 4 | import numpy as np 5 | 6 | import neural_renderer as nr 7 | 8 | class TestPerspective(unittest.TestCase): 9 | def test_case1(self): 10 | vertices = torch.from_numpy(np.array([1,2,10], np.float32)) 11 | v_out = np.array([np.sqrt(3) / 10, 2 * np.sqrt(3) / 10, 10], np.float32) 12 | vertices = vertices[None, None, :] 13 | transformer = nr.perspective(vertices) 14 | assert(np.allclose(transformer.data.squeeze().numpy(), v_out)) 15 | 16 | if __name__ == '__main__': 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_renderer.py: -------------------------------------------------------------------------------- 1 | # TODO 2 | ''' 3 | Might have to do some refactoring because the tests for Renderer are included in the test_rasterize* unit tests 4 | ''' 5 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_save_obj.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | import torch 5 | import numpy as np 6 | 7 | import neural_renderer as nr 8 | 9 | current_dir = os.path.dirname(os.path.realpath(__file__)) 10 | data_dir = os.path.join(current_dir, 'data') 11 | 12 | class TestCore(unittest.TestCase): 13 | def test_save_obj(self): 14 | teapot = os.path.join(data_dir, 'teapot.obj') 15 | teapot2 = os.path.join(data_dir, 'teapot2.obj') 16 | vertices, faces = nr.load_obj(teapot) 17 | nr.save_obj(teapot2, vertices, faces) 18 | vertices2, faces2 = nr.load_obj(teapot2) 19 | os.remove(teapot2) 20 | assert torch.allclose(vertices, vertices2) 21 | assert torch.allclose(faces, faces2) 22 | 23 | def test_texture(self): 24 | pass 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /neural_renderer/tests/test_vertices_to_faces.py: -------------------------------------------------------------------------------- 1 | # TODO 2 | -------------------------------------------------------------------------------- /neural_renderer/tests/testn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfzhang95/BMP/6d779c1467f11c0a7aefc9d7e014e97e218452d3/neural_renderer/tests/testn.png -------------------------------------------------------------------------------- /neural_renderer/tests/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import torch 4 | 5 | import neural_renderer as nr 6 | 7 | current_dir = os.path.dirname(os.path.realpath(__file__)) 8 | data_dir = os.path.join(current_dir, 'data') 9 | 10 | 11 | def to_minibatch(data, batch_size=4, target_num=2): 12 | ret = [] 13 | for d in data: 14 | device = d.device 15 | d2 = torch.unsqueeze(torch.zeros_like(d), 0) 16 | r = [1 for _ in d2.shape] 17 | r[0] = batch_size 18 | d2 = torch.unsqueeze(torch.zeros_like(d), 0).repeat(*r).to(device) 19 | d2[target_num] = d 20 | ret.append(d2) 21 | return ret 22 | 23 | def load_teapot_batch(batch_size=4, target_num=2): 24 | vertices, faces = nr.load_obj(os.path.join(data_dir, 'teapot.obj')) 25 | textures = torch.ones((faces.shape[0], 4, 4, 4, 3), dtype=torch.float32) 26 | vertices, faces, textures = to_minibatch((vertices, faces, textures), batch_size, target_num) 27 | return vertices, faces, textures 28 | -------------------------------------------------------------------------------- /preprocess_datasets/full/README.md: -------------------------------------------------------------------------------- 1 | For other datasets, please refer to [here](https://github.com/JiangWenPL/multiperson/tree/master/misc/preprocess_datasets/full). -------------------------------------------------------------------------------- /preprocess_datasets/full/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from tqdm import trange 3 | import os 4 | import cv2 5 | from PIL import Image 6 | import argparse 7 | 8 | def gather_per_image(x, img_dir): 9 | filenames = x['filename'] 10 | indices = np.argsort(filenames) 11 | x = {k: v[indices] for k,v in x.items()} 12 | filenames = x['filename'] 13 | 14 | image_boxes = [[]] 15 | old_name = str(filenames[0]) 16 | img_count = 0 17 | for i in range(len(filenames)): 18 | name = str(filenames[i]) 19 | if name != old_name: 20 | img_count += 1 21 | image_boxes.append([]) 22 | old_name = name 23 | image_boxes[img_count].append(i) 24 | 25 | data = [{} for _ in range(len(image_boxes))] 26 | img_shapes = [] 27 | for i in trange(len(image_boxes)): 28 | for key in x.keys(): 29 | data[i][key] = x[key][image_boxes[i]] 30 | height = data[i]['height'][0] 31 | width = data[i]['width'][0] 32 | data[i]['filename'] = data[i]['filename'][0] 33 | data[i]['height'] = data[i]['height'][0] 34 | data[i]['width'] = data[i]['width'][0] 35 | data[i]['bboxes'][:, :2] = np.maximum(data[i]['bboxes'][:, :2], np.zeros_like(data[i]['bboxes'][:, :2])) 36 | data[i]['bboxes'][:, 2] = np.minimum(data[i]['bboxes'][:, 2], width * np.ones_like(data[i]['bboxes'][:, 2])) 37 | data[i]['bboxes'][:, 3] = np.minimum(data[i]['bboxes'][:, 3], height * np.ones_like(data[i]['bboxes'][:, 3])) 38 | return data 39 | 40 | 41 | def vectorize_distance(a, b): 42 | """ 43 | Calculate euclid distance on each row of a and b 44 | :param a: Nx... np.array 45 | :param b: Mx... np.array 46 | :return: MxN np.array representing correspond distance 47 | """ 48 | N = a.shape[0] 49 | a = a.reshape ( N, -1 ) 50 | M = b.shape[0] 51 | b = b.reshape ( M, -1 ) 52 | a2 = np.tile ( np.sum ( a ** 2, axis=1 ).reshape ( -1, 1 ), (1, M) ) 53 | b2 = np.tile ( np.sum ( b ** 2, axis=1 ), (N, 1) ) 54 | dist = a2 + b2 - 2 * (a @ b.T) 55 | return np.sqrt(dist) -------------------------------------------------------------------------------- /preprocess_datasets/pretrain/process_data.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os.path as osp 3 | import numpy as np 4 | from tqdm import tqdm 5 | 6 | pkl_file = 'mpi_inf_3dhp/train.pkl' 7 | data = pickle.load(open(pkl_file, 'rb')) 8 | for i, data_i in tqdm(enumerate(data)): 9 | filename = data_i['filename'].split('/')[-1] 10 | bboxes = np.array(data_i['bboxes']) 11 | kpts2d = np.array(data_i['kpts2d']) 12 | kpts3d = np.array(data_i['kpts3d']) 13 | assert bboxes.shape == (1, 4) 14 | assert kpts2d.shape == (1, 24, 3) 15 | assert kpts3d.shape == (1, 24, 4) 16 | data[i]['filename'] = filename 17 | data[i]['bboxes'] = bboxes 18 | data[i]['kpts2d'] = kpts2d 19 | data[i]['kpts3d'] = kpts3d 20 | 21 | with open(pkl_file, 'wb') as f: 22 | pickle.dump(data, f) -------------------------------------------------------------------------------- /sdf/README.md: -------------------------------------------------------------------------------- 1 | ## Implementation of the SDF Loss 2 | 3 | In this package we provide a CUDA implementation of the SDF computation as well as of the SDF-based collision function. 4 | 5 | ## Installation instructions 6 | 7 | You can install the package by running 8 | ``` 9 | python setup.py install 10 | ``` 11 | 12 | # Acknowledgements 13 | 14 | Our SDF CUDA kernels are based on the [original](https://github.com/davidstutz/mesh-voxelization) C++ implementation by [David Stutz](https://github.com/davidstutz). 15 | 16 | ## Citing 17 | 18 | If you find this code useful for your research or the use data generated by our method, please consider citing the following paper: 19 | ''' 20 | @Inproceedings{jiang2020mpshape, 21 | Title = {Coherent Reconstruction of Multiple Humans from a Single Image}, 22 | Author = {Jiang, Wen and Kolotouros, Nikos and Pavlakos, Georgios and Zhou, Xiaowei and Daniilidis, Kostas}, 23 | Booktitle = {CVPR}, 24 | Year = {2020} 25 | } 26 | ''' 27 | -------------------------------------------------------------------------------- /sdf/sdf/__init__.py: -------------------------------------------------------------------------------- 1 | from .sdf import sdf, SDF 2 | from .sdf_loss import SDFLoss 3 | from .collisionvolume import CollisionVolume 4 | -------------------------------------------------------------------------------- /sdf/sdf/csrc/sdf_cuda.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define CHECK_CUDA(x) AT_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") 4 | #define CHECK_CONTIGUOUS(x) AT_CHECK(x.is_contiguous(), #x " must be contiguous") 5 | #define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) 6 | 7 | // CUDA forward declarations 8 | 9 | at::Tensor sdf_cuda( 10 | at::Tensor phi, 11 | at::Tensor faces, 12 | at::Tensor vertices); 13 | 14 | at::Tensor sdf( 15 | at::Tensor phi, 16 | at::Tensor faces, 17 | at::Tensor vertices) { 18 | 19 | CHECK_INPUT(phi); 20 | CHECK_INPUT(faces); 21 | CHECK_INPUT(vertices); 22 | 23 | return sdf_cuda(phi, faces, vertices); 24 | } 25 | 26 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 27 | m.def("sdf", &sdf, "SDF (CUDA)"); 28 | } 29 | -------------------------------------------------------------------------------- /sdf/sdf/sdf.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torch.autograd import Function 5 | 6 | import sdf.csrc as _C 7 | 8 | class SDFFunction(Function): 9 | """ 10 | Definition of SDF function 11 | """ 12 | 13 | @staticmethod 14 | def forward(ctx, phi, faces, vertices): 15 | return _C.sdf(phi, faces, vertices) 16 | 17 | @staticmethod 18 | def backward(ctx): 19 | return None, None, None 20 | 21 | class SDF(nn.Module): 22 | 23 | def forward(self, faces, vertices, grid_size=32): 24 | phi = torch.zeros(vertices.shape[0], grid_size, grid_size, grid_size, device=vertices.device) 25 | phi = SDFFunction.apply(phi, faces, vertices) 26 | return phi 27 | 28 | def sdf(faces, vertices, grid_size=32): 29 | phi = torch.zeros(vertices.shape[0], grid_size, grid_size, grid_size, device=vertices.device) 30 | return sdf_cuda.sdf(phi, faces, vertices) 31 | -------------------------------------------------------------------------------- /sdf/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 4 | 5 | CUDA_FLAGS = [] 6 | INSTALL_REQUIREMENTS = [] 7 | 8 | ext_modules=[ 9 | CUDAExtension('sdf.csrc', [ 10 | 'sdf/csrc/sdf_cuda.cpp', 11 | 'sdf/csrc/sdf_cuda_kernel.cu', 12 | ]), 13 | ] 14 | 15 | setup( 16 | description='PyTorch implementation of SDF loss', 17 | author='Nikos Kolotouros', 18 | author_email='nkolot@seas.upenn.edu', 19 | license='MIT License', 20 | version='0.0.1', 21 | name='sdf_pytorch', 22 | packages=['sdf', 'sdf.csrc'], 23 | install_requires=INSTALL_REQUIREMENTS, 24 | ext_modules=ext_modules, 25 | cmdclass = {'build_ext': BuildExtension} 26 | ) 27 | --------------------------------------------------------------------------------